오류가 발생하면 'find'가 0이 아닌 종료 코드를 반환하게 됩니다.

오류가 발생하면 'find'가 0이 아닌 종료 코드를 반환하게 됩니다.

왜 다음이 표시됩니까?

$ find  -not -exec bash -c 'foo' \; -quit
bash: foo: command not found
$ echo $?
0

이것은 제가 사용하고 있는 실제 스크립트의 단순화된 버전입니다. (정말 알고 싶으시다면) 질문 끝에 게시하겠습니다.

따라서 문제는 find여러 개의 찾기 결과로 쉘을 실행하고 첫 번째 결과가 실패할 때 종료하는 방법입니다.exec bash -c그리고또한 나중에 스크립트에서 확인할 수 있는 0이 아닌 종료 코드를 반환합니까?

*실제 스크립트*

#!/usr/bin/env bash
find path-a path-b path-c \
  -iname build.xml -not -exec bash -c 'echo -n "building {} ..." && ant -f {} build && echo "success" || (echo "failure" && exit 1)' \; -quit
RESULT=$?
echo "result was $RESULT"

답변1

이렇게 하면 트릭이 수행됩니다.

#!/bin/bash
RESULT=0
while IFS= read -r -u3 -d $'\0' file; do
        echo -n "building $file ..."
        ant -f "$file" build &&
           echo "success" ||
           { echo "failure" ; RESULT=1 ; break; }
done 3< <(find path-a path-b path-c  -print0)

echo "result was $RESULT"

그림과 같이 루프 find와 혼합되어 있습니다 .bash여기.

$?변수를 직접 사용 하지 않습니다 $RESULT.

$RESULT모든 것이 잘 진행 되면 0, 그렇지 않으면 1입니다. 오류가 발생하면 루프가 중단됩니다.

(사용으로 인해 -print0) 악성 파일 이름으로부터 안전해야 합니다.

답변2

find 명령을 사용하면 종료 코드를 설정하는 데 어려움이 있습니다. 그 이유는 두 가지 유형의 입력(지금은 옵션은 잊어버리세요)과 두 가지 작업 유형이 있기 때문입니다.

  1. 찾고 있는 파일의 경로입니다. 예를 들어 이렇게 하면 오류가 발생하여 종료되는 것을 원하지 않을 것입니다 find /mnt/log/storage/place -type f -mtime +7 -print. 로그 저장소에는 7일이 지나지 않은 파일이 있을 수 있으므로 해당 파일을 건너뛰는 것은 오류가 아닙니다. 이는 귀하의 의도입니다. /mnt/log/storage/place경로에 전혀 들어갈 수 없다면 그것은 버그입니다 .
  2. 찾기 작업을 제어하는 ​​표현식입니다. 표현식의 요소는 true 또는 false입니다. 이 목적에 따라 -exec실행 중인 명령이 0을 반환하면 true이고 0이 아닌 값을 반환하면 false입니다. 변경된 동작으로 -exec인해 find의 다른 모든 표현 요소 중에서 고유하게 되며 전 세계의 많은 기존 스크립트가 중단될 가능성이 높습니다.

따라서 문제에 대한 또 다른 해결책: whileLatinSuD 루프와 유사한 작업을 수행할 수 있습니다. 변수에서 명령 상태를 확인할 수 있지만 더 간단합니다.

errorout=$(find /tmp -type f \( -exec bash -c '/tmp/doit 1>/tmp/stdoutfile' \; -o -quit \) 2>&1 )

스크립트가 /tmp/doit실행 가능하지 않거나 stderr로 출력을 생성하는 경우 errorout 변수가 채워집니다. 오류를 테스트하고 다음과 같이 반응하십시오.

[ -n "$errorout" ] || { echo 'Oh no- an error from find!'; /do/something/else; }

한 줄에 대해 다음을 수행할 수 있습니다.

errorout=$(find /tmp -type f \( -exec bash -c '/bin/false || { echo "error" 1>&2; exit 1; }' \; -o -quit \) 2>&1 )

/bin/false원하는 명령으로 바꾸십시오 . 다음과 같은 명령 목록을 실행할 수 있습니다.

errorout=$(find /tmp -type f \( -exec bash -c '{ command1 && command2 && command3; } || { echo "error" 1>&2; exit 1; }' \; -o -quit \) 2>&1 )

목록의 명령이 처음 실패할 때 즉시 종료하고 싶지 않은 경우:

errorout=$(find /tmp -type f \( -exec bash -c '{ command1; command2; command3; } || { echo "error" 1>&2; exit 1; }' \; -o -quit \) 2>&1 )

...명령 문자열에서 닫는 중괄호 앞에 있는 세미콜론을 잊지 마세요.

관련 정보