Subshell
為什麼在所有子shell之後不執行此腳本中的等待?
在這個腳本中,它會拉取所有 git 儲存庫:
#!/bin/bash find / -type d -name .git 2>/dev/null | while read gitFolder; do if [[ $gitFolder == *"/Temp/"* ]]; then continue; fi if [[ $gitFolder == *"/Trash/"* ]]; then continue; fi if [[ $gitFolder == *"/opt/"* ]]; then continue; fi parent=$(dirname $gitFolder); echo ""; echo $parent; (git -C $parent pull && echo "Got $parent") & done wait echo "Got all"
不
wait
等待所有git pull
子shell。為什麼會這樣,我該如何解決?
問題是
wait
由錯誤的shell程序執行。在bash
中,管道的每個部分都在單獨的子外殼中執行。後台任務屬於執行while
循環的子shell。將其wait
移入該子外殼將使其按預期工作:find ... | { while ...; do ... ( git -C ... && ... ) & done wait } echo 'done.'
您還有一些未加引號的變數。
我會完全擺脫管道,而是
find
直接執行循環,這樣就不需要解析find
.find / -type d -name .git \ ! -path '*/Temp/*' \ ! -path '*/opt/*' \ ! -path '*/Trash/*' \ -exec sh -c ' for gitpath do git -C "$gitpath"/.. pull & done wait' sh {} +
或者,
-prune
用於避免進入我們不想處理的任何子目錄,find / \( -name Temp -o -name Trash -o -name opt \) -prune -o \ -type d -name .git -exec sh -c ' for gitpath do git -C "$gitpath"/.. pull & done wait' sh {} +
正如評論中提到的,您還可以
xargs
更好地控制並發執行的git
程序數。下面使用的-P
選項(用於指定並發任務的數量)是非標準的,-0
(用於讀取\0
- 分隔的路徑名)和-r
(用於避免在沒有輸入時執行命令)也是如此。不過, GNUxargs
和該實用程序的其他一些實現具有這些選項。此外,(to output -delimited pathnames) 的-print0
謂詞是非標準的,但通常實現。find``\0
find / \( -name Temp -o -name Trash -o -name opt \) -prune -o \ -type d -name .git -print0 | xargs -t -0r -P 4 -I {} git -C {}/.. pull
我確信 GNU
parallel
也可以以類似的方式使用,但由於這不是這個問題的主要焦點,所以我不追求那種構想。