SO의 Q & A에서 가져온 다음 방법을 사용하여 파일 이름을 배열로 구문 분석하는 스크립트가 있습니다 .
unset ARGS
ARGID="1"
while IFS= read -r -d $'\0' FILE; do
ARGS[ARGID++]="$FILE"
done < <(find "$@" -type f -name '*.txt' -print0)
이것은 훌륭하게 작동하며 모든 유형의 파일 이름 변형을 완벽하게 처리합니다. 그러나 때로는 존재하지 않는 파일을 스크립트에 전달합니다.
$ findscript.sh existingfolder nonexistingfolder
find: `nonexistingfile': No such file or directory
...
정상적인 상황에서 스크립트는 종료 코드를 비슷한 것으로 캡처하고 RET=$?
진행 방법을 결정하는 데 사용합니다. 위의 프로세스 대체에서는 작동하지 않는 것 같습니다.
이와 같은 경우 올바른 절차는 무엇입니까? 리턴 코드를 어떻게 캡처 할 수 있습니까? 대체 프로세스에서 문제가 발생했는지 확인하는 다른 적절한 방법이 있습니까?
답변
stdout을 통해 리턴을 에코하여 서브 쉘 프로세스에서 리턴을 쉽게 얻을 수 있습니다. 프로세스 대체도 마찬가지입니다.
while IFS= read -r -d $'\0' FILE ||
! return=$FILE
do ARGS[ARGID++]="$FILE"
done < <(find . -type f -print0; printf "$?")
– 그럼 내가 매우 마지막 줄 것을 실행하면 (또는 \0
경우에 따라 구분 된 섹션) 이 될 것입니다 find
‘의 반환 상태. read
EOF를 받으면 1을 반환하므로 마지막으로 읽은 정보의 마지막 시간 만 $return
설정됩니다 $FILE
.
printf
여분의 \n
ewline 을 추가하는 것을 피하기 위해 사용 합니다. 이것은 중요합니다. read
정기적으로 수행 된 조차도-NUL을 제한하지 않는- 조차도 \0
읽은 데이터가 끝나지 않는 경우 0 이외의 값을 반환 하기 때문에 중요 합니다 \n
ewline. 따라서 마지막 줄이 \n
ewline으로 끝나지 않으면 읽은 변수의 마지막 값이 반환됩니다.
위의 명령을 실행 한 후 다음을 수행하십시오.
echo "$return"
산출
0
그리고 프로세스 대체 부분을 변경하면 …
...
done < <(! find . -type f -print0; printf "$?")
echo "$return"
산출
1
더 간단한 데모 :
printf \\n%s list of lines printed to pipe |
while read v || ! echo "$v"
do :; done
산출
pipe
실제로, 원하는 대체가 프로세스 대체 또는이 방식으로 읽은 서브 쉘 프로세스에서 stdout에 마지막으로 쓰는 $FILE
것이라면 항상 원하는 리턴 상태가됩니다. 을 통해. 따라서이 || ! return=...
부분은 꼭 필요한 것은 아닙니다. 개념을 설명하는 데만 사용됩니다.
답변
프로세스 대체 프로세스는 비동기식입니다. 셸은 프로세스를 시작한 다음 언제 죽는 지 감지 할 방법을 제공하지 않습니다. 따라서 종료 상태를 얻을 수 없습니다.
종료 상태를 파일에 쓸 수는 있지만 파일이 언제 작성되는지 알 수 없기 때문에 일반적으로 어색합니다. 여기서 파일은 루프가 끝난 직후에 작성되므로 기다릴 수 있습니다.
… < <(find …; echo $? >find.status.tmp; mv find.status.tmp find.status)
while ! [ -e find.status ]; do sleep 1; done
find_status=$(cat find.status; rm find.status)
또 다른 방법은 명명 된 파이프와 백그라운드 프로세스 (가능한 프로세스)를 사용하는 것 wait
입니다.
mkfifo find_pipe
find … >find_pipe &
find_pid=$!
… <find_pipe
wait $find_pid
find_status=$?
두 가지 방법 중 어느 것도 적합하지 않다면 Perl, Python 또는 Ruby와 같이 더 유능한 언어를 사용해야 할 것입니다.
답변
coprocess를 사용하십시오 . coproc
내장을 사용하여 서브 프로세스를 시작하고 출력을 읽고 종료 상태를 확인할 수 있습니다.
coproc LS { ls existingdir; }
LS_PID_=$LS_PID
while IFS= read i; do echo "$i"; done <&"$LS"
wait "$LS_PID_"; echo $?
디렉토리가 존재하지 않으면 wait
0이 아닌 상태 코드로 종료됩니다.
호출 $LS_PID
되기 전에 설정 해제 되므로 PID를 다른 변수에 복사해야합니다 wait
. 자세한 내용 은 coproc 을 기다릴 수 있기 전에 Bash unsets * _PID 변수 를 참조하십시오.
답변
한 가지 방법은 다음과 같습니다.
status=0
token="WzNZY3CjqF3qkasn" # some random string
while read line; do
if [[ "$line" =~ $token:([[:digit:]]+) ]]; then
status="${BASH_REMATCH[1]}"
else
echo "$line"
fi
done < <(command; echo "$token:$?")
echo "Return code: $status"
아이디어는 명령이 완료된 후 임의의 토큰과 함께 종료 상태를 반향 한 다음 bash 정규식을 사용하여 종료 상태를 찾고 추출하는 것입니다. 토큰은 출력에서 찾을 고유 한 문자열을 작성하는 데 사용됩니다.
일반적인 프로그래밍 의미에서 가장 좋은 방법은 아니지만 bash에서 처리하는 것이 가장 고통스러운 방법 일 수 있습니다.