Bash 无法在存储在变量中的路径中的目录中循环

Bash 无法在存储在变量中的路径中的目录中循环,bash,Bash,我就是不明白,为什么我不能做我刚才在问题中提到的事情 为了得到更多的澄清,我试图循环遍历某个路径中的所有目录,该路径存储在我选择的任何随机变量中。请查看下面的脚本,让我知道为什么在运行脚本时执行没有通过for循环开始语句: gpll_allrepos3() { export SIMPROJS="/c/Projects/mainproject" currPath=$(pwd) for repoFolder in $SIMPROJS; do echo "Rep

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

为了得到更多的澄清,我试图循环遍历某个路径中的所有目录,该路径存储在我选择的任何随机变量中。请查看下面的脚本,让我知道为什么在运行脚本时执行没有通过
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脚本编写者,因此任何建议都值得赞赏,但请注意,我需要能够从我选择的任何地方运行此脚本。

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

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
变量中的任何内容)将变量的内容拆分为单独的单词,并在变量的值中展开通配符,而您通常不希望这样做(如果意外发生,可能会引起麻烦)。另一方面,
*
必须在双引号之外,这样它将扩展到文件列表,而不仅仅被视为文本文件名

另外,请注意,这将迭代/c/Projects/mainproject中的文件和子目录。如果只需要子目录,请使用以下命令:

for repoFolder in "$SIMPROJS"/*/; do
添加的尾部斜杠将其限制为仅匹配目录(因为在目录路径末尾的斜杠有意义,但在普通文件路径末尾的斜杠没有意义)。但是请注意,后面的斜杠也将包含在结果路径中

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

另外,当您在脚本中使用
cd
时,应该始终包括错误处理,以防由于某种原因失败。否则,脚本将继续在错误的位置运行,可能导致混乱。您使用:

cd "$SIMPROJS/$repoFolder" && echo "Now inside $SIMPROJS/$repoFolder"
…如果失败(这是由于路径加倍问题),它将不会打印“Now inside…”消息,但随后将继续执行其他所有操作。您应该使用更像这样的内容:

cd "$repoFolder" || {
    echo "Couldn't cd into $repoFolder, cancelling..." >&2
    return 1
}
…这将退出功能,而不是盲目地在错误的位置继续


顺便说一句,善于发现这些常见问题;我建议您至少在熟悉shell脚本之前先运行脚本。

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

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
变量中的任何内容)将变量的内容拆分为单独的单词,并在变量的值中展开通配符,而您通常不希望这样做(如果意外发生,可能会引起麻烦)。另一方面,
*
必须在双引号之外,这样它将扩展到文件列表,而不仅仅被视为文本文件名

另外,请注意,这将迭代/c/Projects/mainproject中的文件和子目录。如果只需要子目录,请使用以下命令:

for repoFolder in "$SIMPROJS"/*/; do
添加的尾部斜杠将其限制为仅匹配目录(因为在目录路径末尾的斜杠有意义,但在普通文件路径末尾的斜杠没有意义)。但是请注意,后面的斜杠也将包含在结果路径中

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

另外,当您在脚本中使用
cd
时,应该始终包括错误处理,以防由于某种原因失败。否则,脚本将继续在错误的位置运行,可能导致混乱。您使用:

cd "$SIMPROJS/$repoFolder" && echo "Now inside $SIMPROJS/$repoFolder"
…如果失败(这是由于路径加倍问题),它将不会打印“Now inside…”消息,但随后将继续执行其他所有操作。您应该使用更像这样的内容:

cd "$repoFolder" || {
    echo "Couldn't cd into $repoFolder, cancelling..." >&2
    return 1
}
…这将退出功能,而不是盲目地在错误的位置继续

顺便说一句,善于发现这些常见问题;我建议您在le运行您的脚本