프로세스 대체를 사용하여 오류를 감지하는 방법

프로세스 대체를 사용하여 오류를 감지하는 방법

이 질문은 다음 질문과 유사합니다.협회, 그러나 명령줄(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

다른 쉘도 비슷한 설정을 제공할 수 있습니다.

관련 정보