BASH Linux-如何将find的结果传递给for循环

时间:2017-09-24 20:32:36

标签: bash sh

我得到一个包含不同Git repos的本地目录。目录树是这样的:

rid gamedate    hid home    Home Score  vid visitor Visitor Score
-----------------------------------------------------------------    
183 08/31/2017  4   Aliso           3   15  Beck        2
187 08/31/2017  7   Martin Luther   3   15  Beck        2
161 09/05/2017  25  Burrou          16  15  Beck        18
261 09/20/2017  4   Aliso           12  137 Mission     2
211 08/25/2017  25  Burrou          14  137 Mission     7

我想创建一个使用Dir - dir1 --- repo1 - dir2 --- repo2 - dir3 --- repo3 命令获取所有find目录名的Bash脚本,然后将.git循环中的所有路径传递给{{1}来自远程仓库的所有更新。 因此,我可以通过运行此bash脚本来更新所有repos。

任何人都可以提示如何做到这一点吗?相关文档也很有帮助。

5 个答案:

答案 0 :(得分:2)

目前还不清楚您的所有存储库是否都位于同一目录级别,但它们似乎来自您的问题。从这个角度来看,没有必要调用find,只需使用globbing,例如

for dir in */; do                     ## for each dir under present
    if [ -d "$dir/.git" ]; then       ## does it have a .git dir?
        pushd "$dir" >/dev/null 2>&1  ## if so, change to it
        git pull                      ## update repo
        popd >/dev/null 2>&1          ## change back to original dir
    fi
done

有很多变化。我使用pushdpopd来避免解析路径或使用..。如果您愿意,可以cd "$dir"然后cd ..

目录不是全部在同一级别,您可以使用find,如果您正在寻找最短的实现,它可能会像:

cwd="$PWD"                                        ## save current path
for dir in $(find . -type d -name "*\.git"); do   ## loop over all with .git
    dname="${dir#./}"                             ## trim leading './'
    cd "$cwd/${dname%/.git}" && git pull          ## change to and git pull
done

让我知道这对你有好处。

答案 1 :(得分:2)

我将建议一种相当不同的方法,一种利用find运行命令的能力。

cd Dir             # Change to the top-level directory
find . -type d -name .git -exec \
     sh -c 'for d in "$@"; do (cd "$d/.."; git pull) done' argv0 {} +

这会将目录更改为顶级目录,然后运行find以找到.git目录。执行-exec后的命令,每个Git目录名称代替脚本中的{}+表示将使用方便的名称。单一命令执行。执行的命令是:

sh -c 'for d in "$@"; do (cd "$d/.." && git pull) done' argv0 dir1/.git dir2/.git …

argv0参数是通过$0运行的shell脚本的-c '…' - 如果您愿意,可以使用git-multi-pull之类的名称。该脚本依次处理每个参数,仔细保留空格,通过(cd "$d/.." && git pull)将目录更改为存储库的顶级目录并运行git pull(…)在子shell中运行操作,这意味着如果存在问题(很难看到它会是什么,但以防万一),只有一个子子shell受到影响。没有必要尝试回到下一个cd的正确位置 - 退出前一个子shell而不影响sh -c '…' shell。这样做的好处是文件名中的所有偏心字符都可以自动完成处理。

这是'在命令行输入'版本。您可以删除cd Dir并在.命令中将"${@:-.}"替换为find,从而将其设置为脚本。然后,您可以将要搜索Git repos的目录指定为命令行参数,或者如果没有命令行参数,则使用当前目录。

您可以在shell脚本中添加pwdecho "$d",以便随时回复目录名称,从而为您提供进度跟踪。如果您愿意,可以证明argv0$0,其中包含:

sh -c 'for d in "$@"; do (cd "$d/.." && echo "$0: $PWD" && git pull) done' git-multi-pull {} +

如果你正在进入神秘的shell脚本,你可以省略in "$@";写for d; do (…) done时隐含着这一点。另请注意,当循环的整个主体是子shell时,在done之前不需要分号; )就足够了。

答案 2 :(得分:0)

EXEC功能

find / "*.git" -type d -exec git pull {} \;

你可以使用find命令的exec函数。它作用于从find获取的结果。在上面,它将从/目录中搜索系统中的所有git目录/ repos,一旦找到目录,它就会对它们进行git pull。

希望这可以解决您的问题

答案 3 :(得分:-1)

你可以这样做:

for i in `find . -type d -name .git`
do
 dir=`dirname $i`
 pushd .
 cd $dir
 git pull
 popd
done

答案 4 :(得分:-1)

您可以强制IFS仅包含\n作为字分隔符,因此您可以执行类似

的操作
IFS='
'               #only a new line.
for i in `find . -type d`
do
    if [ -d "$i/.git" ]
    then
        foo_bar "$i"
    fi
done

这不仅适用于bash,而且适用于标准的bourne shell(包括UNIX(tm)V7 !!!)

编辑1

更好的是

find . -type d ... |\
while read dir
do
    if [ -d "$i/.git" ]
    then
        foo_bar "$i"  # or `basename "$i"` or whatever you like.
    fi
done

当然,您可以使用

直接转到.git存储库
find . -type d -name .git |\
while read git_repo
do
    foo_bar `dirname "$i"`
done

如果你知道所有的回购都在这个水平之下,那就去做

for repo in */.git
do
    repo_name=`dirname "$repo"`
    foo_bar "$repo_name"
done

例如,正如您在问题中注意到的那样

for repo in */.git
do
    (   cd `dirname "$repo"`
        git pull
    )   # subshell it to conserve current dir in parent shell.
done

(语法与所有Bourne Shell兼容,而不是特定于bash(1))