无法循环访问存储在变量中的目录

时间:2018-11-06 20:58:57

标签: bash

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

为进一步说明,我试图遍历某个路径中的所有目录,该目录存储在我选择的任何随机变量中。请查看下面的脚本,让我知道为什么在运行脚本时为什么执行没有经过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脚本编写者,因此可以提出任何建议,但请注意,我需要能够从我选择的任何位置运行此脚本。

3 个答案:

答案 0 :(得分:1)

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

此外,请注意,这将遍历文件和/ 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
}

...这将退出功能,而不是盲目地在错误的位置继续执行。

BTW,shellcheck.net善于发现此类常见问题;我建议至少通过它来运行脚本,直到您对Shell脚本更加熟悉为止。

答案 1 :(得分:1)

要遍历目录中的文件,您需要提供一个可以为expanded to a filename glob的字符串。

有了它,循环变量将包含整个路径,因此无需在原始目录名称前加上前缀。

此外,您可以使用pushdpopd来避免创建$currPath变量。

#!/bin/bash
simprojs="/c/Projects/mainproject"
for repoFolder in "$simprojs"/*; do
    if [[ -d "$repoFolder/.git" && ! -L "$repoFolder/.git" ]]; then
        pushd "$repoFolder" && echo "Now inside $repoFolder"
        curr_branch=$(git rev-parse --abbrev-ref HEAD)
        git checkout master
        git pull && git pull origin
        git checkout "$curr_branch"
        git merge master
    fi
done
popd

答案 2 :(得分:1)

脚本似乎已解决了问题,可以使用findfind $SOMEPATH -type d -name .git -execdir git checkout master \; -execdir git pull && git pull origin \; -execdir ... \;

find中名为“ .git”(-type d)的

-name .git目录($SOMEPATH)。对于每个.git目录,从包含匹配文件(command)的子目录中运行-execdir command \; -execdir command \; -execdir ... \;

您不需要{。{1}}到.git目录,也不需要维护一堆目录(例如cdpushd),等等。衬垫。注意:默认情况下,popd从不跟随符号链接(参见op的find)。