이 스크립트에서 기다린 후에 모든 하위 쉘이 실행되지 않는 이유는 무엇입니까?

이 스크립트에서 기다린 후에 모든 하위 쉘이 실행되지 않는 이유는 무엇입니까?

이 스크립트에서는 모든 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.

왜 이런 일이 발생합니까? 어떻게 해결할 수 있나요?

답변1

문제는 wait잘못된 쉘 프로세스에 의해 실행되고 있습니다. 에서는 bash파이프라인의 각 부분이 별도의 하위 셸에서 실행됩니다. 백그라운드 작업은 while루프를 실행하는 하위 셸 에 속합니다 . 이 하위 셸로 이동하면 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(입력 없이 명령 실행 방지)입니다. 그러나 GNU xargs와 이 유틸리티의 일부 다른 구현에는 이러한 옵션이 있습니다. 또한 조건자(출력으로 구분된 경로 이름)는 -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하지만 그것이 이 질문의 주요 초점이 아니기 때문에 나는 그런 사고 방식을 추구하지 않습니다.

관련 정보