Subshell

為什麼在所有子shell之後不執行此腳本中的等待?

  • January 28, 2022

在這個腳本中,它會拉取所有 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

我確信 GNUparallel也可以以類似的方式使用,但由於這不是這個問題的主要焦點,所以我不追求那種構想。

引用自:https://unix.stackexchange.com/questions/688207