-exec가 실패하면 어떻게 찾을 수 없습니까?


29

쉘에서 (빈 디렉토리가 아닌)이 명령을 실행할 때 :

find . -exec invalid_command_here {} \;

나는 이것을 얻는다 :

find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory

(각 파일마다)

find첫 번째 오류 후에 실패 해야 합니다. 이 작업을 수행 할 수있는 방법이 있습니까? xargs경로에 공백이 있으므로을 사용할 수 없지만 오류 코드를 반환하려면 이것을 호출하는 스크립트가 필요합니다.

답변:


34

의 제한 사항입니다 find. POSIX 표준 의 반환 상태가되도록 지정 find오류가 디렉토리를 통과하면서 발생하지 않는 0; 실행 된 명령의 반환 상태는 입력되지 않습니다.

명령이 파일이나 설명자에 상태를 쓰도록 할 수 있습니다.

find_status_file=$(mktemp findstatus)
: >"$find_status_file"
find  -exec sh -c 'trap "echo \$?" EXIT; invalid_command "$0"' {} \;
if [ -s "$find_status_file" ]; then
  echo 1>&2 "An error occurred"
fi
rm -f "$find_status_file"

또 다른 방법은, 당신이 발견으로 , xargs를 사용하는 것입니다. xargs명령은 항상 모든 파일을 처리하지만, 상태 1 명령 반환의 제로가 아닌 상태의 경우를 반환합니다.

find  -print0 | xargs -0 -n1 invalid_command

또 다른 방법은 find쉘에서 재귀 globbing 을 피하고 사용 **/하는 것입니다. 하위 디렉토리의 깊이를 의미합니다. 여기에는 bash 버전 4 이상이 필요합니다. macOS는 버전 3.x에 고정되어 있으므로 포트 컬렉션에서 설치해야합니다. set -e0이 아닌 상태를 리턴하는 첫 번째 명령에서 스크립트를 중지하는 데 사용하십시오 .

shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done

bash 4.0에서 4.2까지는 작동하지만 디렉토리에 대한 심볼릭 링크를 통과하므로 일반적으로 바람직하지 않습니다.

bash 대신 zsh를 사용하면 재귀 적 글 로빙이 문제없이 작동합니다. Zsh는 기본적으로 OSX / macOS에서 사용할 수 있습니다. zsh에서는 다음과 같이 쓸 수 있습니다.

set -e
for x in **/*.xml; do invalid_command "$x"; done

xargs접근법은 일반적으로 작동하지만 어떻게 든 bash -c명령을 위반 합니다. 예를 들면 다음과 같습니다 find . -name '*.xml' -print0 | xargs -0 -n 1 -I '{}' bash -c "foo {}".. 이것은 여러 번 실행되는 반면 find . -name '2*.xml' -print0 | xargs -0 -n 1 -I '{}' foo {}한 번 실행되어 실패합니다. 왜 그런지 알아?
DKroot

@DKroot {}내부 에서는 절대 사용하지 마십시오 bash -c. 파일 이름을 가져 와서 쉘 명령 안에 직접 삽입합니다. 파일 이름에 공백과 같은 쉘에서 특별한 의미가있는 문자가 포함 된 경우 쉘은 이러한 특수 문자를 해석합니다. 쉘이 필요한 경우 {}별도의 인수로 전달 bash -c 'foo "$0"' {}하십시오 ( 예 : 큰 따옴표도 참고 $0).
Gilles 'SO- 악마 그만'

좋아, 질문을 제쳐두고 왜 다음이 첫 번째 오류에서 멈추지 않습니까? find . -name '*' -print0 | xargs -0 -n 1 -I '{}' bash -c 'foo "$0"' {}
DKroot

@DKroot 왜 에러가 발생했을까요? xargs는 항상 모든 항목에서 명령을 실행합니다.
Gilles 'SO- 악마 중지'

이 답변을 사용하려고합니다 : xargs ( find . -print0 | xargs -0 -n1 invalid_command) 접근법. 첫 번째 오류에서 올바르게 중지됩니다 find . -name '*' -print0 | xargs -0 -n 1 -I '{}' foo {}.. 큰! 그러나 동일한 접근 방식이 bash -c(위) 작동하지 않습니다 . 이 둘의 유일한 차이점은 bash -c입니다.
DKroot

18

대신 이것을 사용할 수 있습니다 :

find . -name *.xml -print0 | xargs -n 1 -0 invalid_command

4

xargs하나의 옵션입니다. 그러나 실제로 대신 대신 find사용 하여이 작업을 수행하는 것이 쉽지 않습니다.+\;

-exec  utility_name  [argument ...]   {} +

로부터 POSIX 문서 :

1 차 표현식이 더하기 부호로 문장 부호를 붙이면 1 차 표현식은 항상 true로 평가되고 1 차 평가 경로 이름은 집합으로 집계됩니다. utility_name 유틸리티는 집계 된 각 경로 이름 세트마다 한 번씩 호출됩니다. 각 호출은 세트의 마지막 경로 이름이 집계 된 후 시작해야하며 찾기 유틸리티가 종료되기 전과 다음 세트의 첫 번째 경로 이름 (있는 경우)이이 기본에 대해 집계되기 전에 완료되어야합니다. 다른 1 차 평가 이전, 도중 또는 이후에 발생합니다. 호출이 0이 아닌 값을 종료 상태로 리턴하면 찾기 유틸리티는 0이 아닌 종료 상태를 리턴합니다."{}"문자 두 개만 포함 된 인수는 집계 된 경로 이름 세트로 대체되며 각 경로 이름은 집계 된 순서와 동일한 순서로 호출 된 유틸리티에 별도의 인수로 전달됩니다. 둘 이상의 경로 이름 세트의 크기는 유틸리티 실행으로 인해 시스템의 {ARG_MAX} 제한이 초과되지 않도록 제한되어야합니다. 두 문자 "{}"만 포함하는 인수가 둘 이상 있으면 동작이 지정되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.