이 질문은 다음 질문과 유사합니다.협회, 그러나 명령줄(bash 쉘) 사용에 중점을 둡니다.
간단한 예를 사용하여 다음 명령을 실행할 때:
$ cat <(date); echo $?
Fri Jul 7 21:04:38 UTC 2017
0
예상대로 종료 값은 0입니다.
다음 명령은 의도적으로 오류를 발생시키지만 반환 값은 여전히 0입니다.
$ cat <(datE); echo $?
bash: datE: command not found...
Similar command is: 'date'
0
명령줄에서 실행할 때(즉, 스크립트에 넣지 않고도) 프로세스 대체에서 발생하는 오류를 잡을 수 있는 방법이 있나요?
위에 포함된 링크의 솔루션은 명령을 실행하는 스크립트를 종료합니다.
답변1
에서는 bash
프로세스 교체가 백그라운드 작업으로 시작됩니다. 다음 명령을 사용하여 마지막 프로세스 리더의 pid를 얻을 수 있으며 , 다른 백그라운드 작업과 비슷한 방식으로 종료 상태를 얻을 $!
수 있습니다 .wait thatpid
$ bash -c 'cat <(exit 3); wait "$!"; echo "$?"'
3
diff <(cmd1) <(cmd2)
이제 동일한 명령에서 두 개의 프로세스 대체를 사용해야 하는 경우(표시된 대로) 이는 도움이 되지 않습니다.
$ bash -c 'cat <(exit 3) <(exit 4); wait "$!"; echo "$?"'
4
위의 PID가 exit 3
누락되었습니다.
다음 트릭을 사용하여 복원할 수 있습니다.
unset -v p1 p2
x='!'
cat <(exit 3) ${!x#${p1=$!}} <(exit 4) ${!x#${p2=$!}}
두 PID가 모두 저장되어 있지만 $p1
마지막 PID만 셸의 작업 테이블에 삽입되고 거부 대기가 이를 잘못 요구 하므로 $p2
이것은 쓸모가 없습니다.wait
$p1
이 껍질의 자식이 아님$p1
, 아직 종료되지 않은 경우에도 :
$ cat test-script
unset -v p1 p2
x='!'
set -o xtrace
cat <(echo x; exec >&-; sleep 1; exit 3) ${!x#${p1=$!}} <(exit 4) ${!x#${p2=$!}}
ps -fH
wait "$p1"; echo "$?"
wait "$p2"; echo "$?"
$ bash test-script
++ echo x
++ exec
++ sleep 1
+ cat /dev/fd/63 /dev/fd/62
++ exit 4
x
+ ps -fH
UID PID PPID C STIME TTY TIME CMD
chazelas 15393 9820 0 21:44 pts/4 00:00:00 /bin/zsh
chazelas 17769 15393 0 22:19 pts/4 00:00:00 bash test-script
chazelas 17770 17769 0 22:19 pts/4 00:00:00 bash test-script
chazelas 17772 17770 0 22:19 pts/4 00:00:00 sleep 1
chazelas 17776 17769 0 22:19 pts/4 00:00:00 ps -fH
+ wait 17770
test-script: line 6: wait: pid 17770 is not a child of this shell
+ echo 127
127
+ wait 17771
+ echo 4
4
$ ++ exit 3
자세한 내용은 다음을 방문하세요.@mosvy의 답변도착하다비동기 작업을 실행하고 bash에서 종료 코드와 출력을 검색합니다.
답변2
프로세스 대체를 사용하는 또 다른 방법은 /dev/stdin
파이프가 예상대로 작동하도록 arg 파일을 사용하는 것입니다.
set -o pipefail
datE | cat /dev/stdin
위의 예는 약간 조작된 것입니다. cat
파일 인수가 제공되지 않으면 stdin을 읽을 것이기 때문입니다. 명령에 파일을 제공해야 할 때 유용합니다.
답변3
오류 는 별도로 시작되므로 bash
호출 프로세스()에 오류를 전파 하는 관용적인 방법이 없습니다 . 유일하게 cat
연결된 cat
것은 datE
이름이 임시 파일일 수 있으며, /dev/fd/63
그 수명 주기는 포함하는 쉘 문의 수명 주기와 관련이 있습니다.
내가 아는 가장 간단한 해결 방법은 출력을 임시 파일에 넣고 dateE
.
그것은 다음과 같습니다:
# Make a tempfile
tmpfile=$(mktemp)
# Delete the tempfile when this shell process exits
trap "rm ${tmpfile}" 0
# Run the command and check for success
if datE > "${tmpfile}"; then
cat < "${tmpfile}"
else
# Report the error.
fi
그렇긴 하지만, 잘못된 값을 전파하는 데 사용되는 추가 파일을 포함할 수 있는 몇 가지 해킹이 있습니다. 그러나 일반적인 아이디어는 상호 합의된 공유 상태(예: 파일, fifo 대기열 또는 파이프 등)가 없는 한 프로세스는 상위 또는 형제 프로세스를 변경할 수 없으며 변경해서는 안 된다는 것입니다.
답변4
귀하의 예에서 :
cat <(datE); echo $?
오류가 발생 datE
하고 출력이 생성되지 않습니다. 그런 다음 오류 코드가 발생합니다. 그러나 (빈) 입력이 표시되고 cat
아무 것도 씹지 않습니다. 이제 종료 코드는 0입니다.
중간 단계를 제거하면 예상대로 작동합니다.
$ datE; echo $?
datE: command not found
127
bash
파이프라인의 실패 및 포착되지 않은 오류가 있는 경우 중단하려면 다음 두 명령을 실행하십시오.
set -e
set -o pipefail
다른 쉘도 비슷한 설정을 제공할 수 있습니다.