Bash,在 for 循环中使用 2 个数组,然后在 for 循环中使用 2 个数组

问题描述 投票:0回答:2

我有一段代码可以回显文件夹中的文件,该文件夹由两个变量描述。 这很好并且有效。 但是,我现在想列出另一个文件夹结构上的文件。但是我无法将其列出。

DIRS="foo bar live1 live2"
SRCDIR="/mnt/nas/stage/live/live/"

# iterate over all directories
for dirname in "${DIRS}"; do
  # go to source sync directory
  cd "${SRCDIR}/${dirname}"
  # get latest mux file name
  filename=`ls -t *.mux 2>/dev/null |head -n 1`
  echo $filename

  ###There is additional code to work on the files here that uses $dirname

done

然后我想添加另一个目录结构;

DIRS1="foo bar live1 live2"
SRCDIR1="/mnt/nas/stage/live/live/"
DIRS2="test1 test2"
SRCDIR2="/mnt/nas/stage/test/test/"

我必须

for dirname in ${DIRS1} ${DIRS2}
当我收到“没有这样的文件或目录”错误时,这有效, 但后来我无法将 CD 变量更改为 SRCDIR2,我确实想再放一个 for 循环

for dirpath in ${SRCDIR1} ${SRCDIR2}
cd "${dirpath}/${dirname}"

然而,这给出了笛卡尔响应。我怎样才能分开只让 DIR1 在 SRCDIR1 中查找,而 DIR2 在 SRCDIR2 中查找?

查看其他答案,我可能需要使用数组,但不知道如何将其放入代码中。

arrays bash loops variables
2个回答
2
投票

如果您知道目录名称不包含空格,您可以使用一对数组,例如:

  DIRS[1]="foo bar live1 live2"
SRCDIR[1]="/mnt/nas/stage/live/live/"
  DIRS[2]="test1 test2"
SRCDIR[2]="/mnt/nas/stage/test/test/"

for ((id=1; id<=2; id++))
do
    for dir in ${DIRS[id]}                             # no double quotes so that each entry is processed separately
    do
        echo "${SRCDIR[id]}${dir}"
    done
done

这会生成:

/mnt/nas/stage/live/live/foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live1
/mnt/nas/stage/live/live/live2
/mnt/nas/stage/test/test/test1
/mnt/nas/stage/test/test/test2

如果目录名称可能包含空格,则此解决方案(不带引号的

${DIRS[id]}
)不起作用,请考虑:

  DIRS[1]="foo bar live1 live2 'foo bar live{1,2}'"    # 5th entry contains a pair of spaces
SRCDIR[1]="/mnt/nas/stage/live/live/"
  DIRS[2]="test1 test2"
SRCDIR[2]="/mnt/nas/stage/test/test/"

for ((id=1; id<=2; id++))
do
    for dir in ${DIRS[id]}                             # split on whitespace
    do
        echo "${SRCDIR[id]}${dir}"
    done
done

这会生成:

/mnt/nas/stage/live/live/foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live1
/mnt/nas/stage/live/live/live2
/mnt/nas/stage/live/live/'foo                          # 5th entry
/mnt/nas/stage/live/live/bar                           # broken into
/mnt/nas/stage/live/live/live{1,2}'                    # 3 parts
/mnt/nas/stage/test/test/test1
/mnt/nas/stage/test/test/test2

如果目录名称可以包含空格,那么另一种方法是使用硬编码数组名称和名称引用(

declare -n
),例如:

  DIRS1=(foo bar live1 live2 'foo bar live{1,2}')      # 5th entry contains a pair of spaces
SRCDIR1="/mnt/nas/stage/live/live/"
  DIRS2=(test1 test2)
SRCDIR2="/mnt/nas/stage/test/test/"

for ((id=1; id<=2; id++))
do
    declare -n dirs="DIRS${id}"                        # nameref; 1st time dirs is a pointer to DIRS1
    declare -n srcdir="SRCDIR${id}"                    # nameref; 1st time srcdir is a pointer to SRCDIR1

    for dir in "${dirs[@]}"
    do
        echo "${srcdir}${dir}"
    done
done

注意: namerefs 需要

bash 4.3+

这会生成:

/mnt/nas/stage/live/live/foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live1
/mnt/nas/stage/live/live/live2
/mnt/nas/stage/live/live/foo bar live{1,2}             # 5th entry maintains whitespace
/mnt/nas/stage/test/test/test1
/mnt/nas/stage/test/test/test2

正如评论中提到的,理想的解决方案是一对多维数组(例如,

DIRS[1,1]="foo"
);不幸的是
bash
不支持多维数组。

是的,可以通过索引串联来模拟多维数组(例如,

DIRS[1-1]="foo"
),但必要的代码有点混乱。如果感兴趣的话,我会把它留给OP来研究这个想法......


0
投票

考虑到 Bash 数组和关联数组的局限性,以及与间接使用变量相关的许多陷阱,我会考虑使用类似这样的 Shellcheck-clean 代码:

#! /bin/bash -p

#               SRCDIR                      DIRS
#               --------------------------  -----------------------
srcdir_dirs=(   /mnt/nas/stage/live/live    foo bar live1 live2 ''
                /mnt/nas/stage/test/test    'test 1' 'test 2' ''    )

srcdir='' dirname=''
for d in "${srcdir_dirs[@]}"; do
    if [[ -z $d ]]; then
        srcdir=''
    elif [[ -z $srcdir ]]; then
        srcdir=$d
    else
        dirname=$d
        printf '%s/%s\n' "$srcdir" "$dirname"
        # ...
    fi
done
  • 这适用于除旧版 Bash 之外的所有版本(已使用 Bash 3 和 Bash 5 进行测试)。
  • 我已将
    test1
    test2
    替换为
    test 1
    test 2
    ,以证明包含空格的名称不会导致问题。 即使名称中换行也可以。
  • ''
    中的空字符串 (
    srcdir_dirs
    ) 条目分隔定义源目录和多个子目录的条目组。 这是安全的,因为空字符串不是有效的文件或目录名称或路径。
  • srcdir_dirs
    数组可以轻松扩展以处理三个或更多源目录。
  • 请参阅为什么 printf 比 echo 更好? 的已接受且优秀的答案,以解释为什么我使用
    printf
    而不是
    echo
© www.soinside.com 2019 - 2024. All rights reserved.