首页 > 解决方案 > 无法遍历存储在变量中的路径中的目录

问题描述

我只是不明白,为什么我不能做我刚才在问题中提到的事情?

为了进一步说明,我试图遍历某个路径中的所有目录,该路径存储在我选择的任何随机变量中。请查看下面的脚本,让我知道为什么在我运行脚本时执行没有通过for循环开始语句:

gpll_allrepos3() {
    export SIMPROJS="/c/Projects/mainproject"
    currPath=$(pwd)
    for repoFolder in $SIMPROJS; do
        echo "RepoFolder: $repoFolder"
        if [[ -d "$SIMPROJS/$repoFolder/.git" && ! -L "$SIMPROJS/$repoFolder/.git" ]]; then
            echo "$SIMPROJS/$repoFolder"
            cd "$SIMPROJS/$repoFolder" && echo "Now inside $SIMPROJS/$repoFolder"
            curr_branch=$(git rev-parse --abbrev-ref HEAD)
            ## git pull && git pull origin
            ## if [[ "$curr_branch" != "master" ]]; then
                ### Merging master branch as the current branch is feature branch
                git checkout master
                git pull && git pull origin
                git checkout $curr_branch
                git merge master
            ## fi
        fi
    done
    cd $currPath
}
gpll_allrepos3

我不是一个非常好的 Bash 脚本编写者,因此欢迎提出任何建议,但请注意,我需要能够从我选择的任何地方运行此脚本。

标签: bash

解决方案


for不会迭代目录的内容,它会迭代一系列“单词”(基本上是字符串)。因此,这个声明:

for var in alice bob "jimmy joe" /c/Projects/mainproject; do

...将运行其内容四次,首先var设置为“alice”,然后设置为“bob”,然后是“jimmy joe”,然后是“/c/Projects/mainproject”。它不会将其中任何一个视为文件或目录名称,因为您没有要求它这样做。另一方面,shell 将扩展/c/Projects/mainproject/*为目录 /c/Projects/mainproject/ 中的文件列表(包括路径前缀)。因此,您可以使用:

for repoFolder in "$SIMPROJS"/*; do

通配符字符串将扩展为一系列单词(对应于 /c/Projects/mainproject/ 下的文件和目录),然后for将遍历这些单词。

注意变量引用周围的双引号?这样做几乎总是一个好主意,否则 shell 会根据空格(或变量中的任何内容)将变量的内容拆分为单独的单词IFS,并在变量的值中扩展通配符,而您通常不希望这样做(并且如果发生意外,可能会造成麻烦)。另一方面, the*必须在双引号之外,因此它会扩展为文件列表,而不仅仅是被视为文字文件名。

另外,请注意,这将遍历 /c/Projects/mainproject 中的文件和子目录。如果您只想要子目录,请使用:

for repoFolder in "$SIMPROJS"/*/; do

添加的尾部斜杠会将其限制为仅匹配的目录(因为目录路径末尾的斜杠是有意义的,但在普通文件路径的末尾却没有)。但请注意,结尾的斜杠也将包含在生成的路径中。

其他注意事项:不要使用"$SIMPROJS/$repoFolder"etc -repoFolder变量已经包含路径前缀(因为它包含在扩展的通配符字符串中),因此再次添加它会导致麻烦。只需使用"$repoFolder".

此外,当您cd在脚本中使用时,您应该始终包含错误处理,以防由于某种原因失败。否则,脚本会在错误的地方继续运行,很可能会导致混乱。你用:

cd "$SIMPROJS/$repoFolder" && echo "Now inside $SIMPROJS/$repoFolder"

...如果失败(由于路径加倍问题,它会失败),它不会打印“现在在里面...”消息,但会继续处理其他所有内容。你应该使用的是更像这样的东西:

cd "$repoFolder" || {
    echo "Couldn't cd into $repoFolder, cancelling..." >&2
    return 1
}

...这将退出该功能,而不是盲目地在错误的地方继续。

顺便说一句,shellcheck.net擅长发现此类常见问题;我建议通过它运行你的脚本,至少在你更熟悉 shell 脚本之前。


推荐阅读