find로 시작된 명령의 종료 코드를 얻는 방법은 무엇입니까?

find로 시작된 명령의 종료 코드를 얻는 방법은 무엇입니까?

저는 Travis-CI에서 Find를 사용하여 프로그래밍 방식으로 특정 파일 형식을 확인하고 있습니다. (정확히 말하면 쉘체크 체크입니다.)

그러나 find그에 의해 실행된 명령/서브쉘의 종료 코드를 사용하는 경우에는 "메인 스크립트"로 전달되지 않으므로 자연스럽게 폐기됩니다.

예를 들어 다음은 find 명령입니다.

find . -type f -iname "*.sh" -exec sh ./testScripts.sh "{}" \;

./testScripts.sh테스트 결과에 따라 0 또는 >= 1로 종료될 수 있습니다.

올바른 종료 코드로 올바르게 종료되지만 testScripts.sh명령 find의 종료 코드는 항상 "0"입니다. 내가 원하는 건 만약에파일/실행오류, 이 오류는 Travis-CI에 "전파"되었습니다.

어떻게 해야 하나요?

답변1

의견에서 Stephen Kitt의 제안을 사용하십시오.

find . -type f -iname "*.sh" -exec sh -c 'for n; do ./testScripts.sh "$n" || exit 1; done' sh {} +

이렇게 하면 sh -c스크립트가 0이 아닌 종료 상태로 가능한 한 빨리 종료됩니다 testScript.sh. 즉, find0이 아닌 종료 상태로도 종료됩니다.

더하기 기호로 끝나는 경우 기본 경로 이름을 평가하는 경로 이름은 세트로 집계되고 유틸리티는 와 유사하게 세트당 한 번씩 호출됩니다 xargs(1). 0이 아닌 종료 상태로 통화가 종료되면 이 작업 find도 결국 수행됩니다., 그러나 이로 인해 find조기 종료되지는 않습니다.


댓글의 질문에 관해서 :

  1. for n; do ... ; done이상해 보이지만 반복할 수 있는 항목이 없고 for루프가 암시적으로 반복된다는 점을 깨닫는다면 이해가 됩니다 "$@".

  2. sh끝에 있는 꼬리는 $0껍질 에 배치됩니다 sh -c. {}많은 경로 이름으로 대체됩니다 . 거기 에 없으면 sh첫 번째 경로 이름은 종료되고 $0거기에 없기 때문에 루프에서 선택되지 않습니다 $@. $0일반적으로 현재 인터프리터의 이름이 포함됩니다(쉘에서 생성된 오류 메시지에 사용됩니다 sh -c).

답변2

xargsxargs명령이 실패하면 1에서 125(GNU의 경우 123) 사이의 종료 상태로 종료되고, 명령이 실패하고 상태 255로 종료되면 중단됩니다.

(with)의 출력을 안정적으로 사용 xargs하고 명령의 표준 입력을 유지하려면 GNU가 필요합니다. 따라서 GNU와 프로세스 교체를 지원하는 셸을 사용하십시오. 예를 들어 다음과 같습니다.find-print0xargsxargskshzshbash

xargs -n1 -r0a <(find . -type f -iname '*.sh' -print0) sh ./testScripts.sh

또는 첫 번째 실패 시 중단합니다.

xargs -r0a <(find . -type f -iname '*.sh' -print0) sh -c '
  for file do
    sh ./testScripts.sh "$file" || exit 255
  done' sh

find(POSIX 코드)를 사용하여 첫 번째 오류 발생 시 중단 할 수도 있습니다 .

find . -type f -name '*.[sS][hH]' -exec sh -c '
  for file do
    if ! sh ./testScripts.sh "$file"; then
      kill -s PIPE "$PPID"
      exit 1
    fi
  done' sh {} +

(SIGPIPE를 더 적게 사용하십시오.시끄러운신호를 내보내려면 일부 셸을 사용하세요(예 bash: ). 이로 인해 find종료되고 0이 아닌 종료 상태로 반환됩니다.

실패한 명령(여기서는 마지막)의 종료 상태에 대한 정확한 값을 얻으려면 zsh또는 를 사용하고 bash다음을 수행할 수도 있습니다.

ret=0
while IFS= read -rd '' -u3 file; do
  sh ./testScripts.sh "$file" 3<&- || ret=$?
done 3< <(find . -type f -iname '*.sh' -print0)

다음을 사용하더라도 이 작업을 수행할 zsh필요조차 없습니다 find.

set -o extendedglob
ret=0
for file (./**/*(#i).sh(D.)) {
  ./testScripts.sh $file || ret=$?
}

관련 정보