왼쪽 명령이 많은 출력을 생성할 때 대시 파이프 "left|right"에서 왼쪽 명령의 종료 상태를 확인하는 방법

왼쪽 명령이 많은 출력을 생성할 때 대시 파이프 "left|right"에서 왼쪽 명령의 종료 상태를 확인하는 방법

변수 "PIPESTATUS"가 dash.simple 에 있는 것 같습니다.혼자 실행왼쪽 명령이 매우 큰 출력을 생성하므로 작동하지 않습니다. 나는 이 작업을 수행하기 위해 fifo를 사용합니다.

#!/bin/dash
mkfifo command1 command2
dash -c "cat ./content;code=\${?};echo \${code} > command1 &" | dash -c "md5sum;code=\${?};echo \${code} > command2 &"
echo "$(cat ./command1)" "$(cat ./command2)"

그런데 왜 끊었는지 모르겠어요?

답변1

명명된 파이프를 사용하고 두 프로세스를 수동으로 연결할 수 있습니다. 역순으로 시작하면 왼쪽이 전경에서 실행되고 $?평소와 같이 종료 상태를 얻게 됩니다.

#!/bin/sh
dir=$(mktemp -d)
mkfifo "$dir/p"
cat < "$dir/p" > /dev/null &
( echo foo; exit 12; ) > "$dir/p"
echo "exit status: left: $?"
rm -r "$dir"

또는 둘 다 원하는 경우 백그라운드 프로세스의 PID를 가져오고 $!종료 wait상태를 가져옵니다.

#!/bin/sh
dir=$(mktemp -d)
mkfifo "$dir/p"
( echo foo; exit 12; ) > "$dir/p" &          # left-hand side
pidleft=$!
( cat; exit 34; ) < "$dir/p" > /dev/null &   # right-hand side
pidright=$!
wait "$pidleft"; exitleft=$?
wait "$pidright"; exitright=$?
echo "exit status: left: $exitleft right: $exitright"
rm -r "$dir"

파이프의 두 번째 부분을 전경에 그대로 둘 수 있습니다. 저는 단지 대칭적으로 하고 싶었을 뿐입니다.


종료 상태를 파일에 저장하고 거기에서 가져올 수도 있습니다.

#/bin/sh
( somecmd; echo "$?" > exit1 ) | ( cat; echo "$?" > exit2)
echo "exit status: left: $(cat exit1) right: $(cat exit2)"

종료 상태가 단지 몇 바이트에 불과하기 때문에 여기서는 명명된 파이프가 많이 사용되지 않는다고 생각합니다. 쉘은 exit1두 번째 줄에서 및 읽기를 시도하기 전에 파이프가 완료될 때까지 기다립니다 .exit2

명명된 파이프를 사용하려면 읽기 측이 열릴 때까지 파이프 블록에 쓰기 때문에 파이프를 백그라운드에 두어야 합니다.

#/bin/sh
mkfifo exit1 exit2
( somecmd; echo "$?" > exit1 ) | ( cat; echo "$?" > exit2) &
echo "exit status: left: $(cat exit1) right: $(cat exit2)"

그러나 cat파이프를 읽는 s가 어떤 이유로 실행되지 않는 경우 파이프를 쓰는 하위 쉘은 백그라운드에서 무기한 차단됩니다.

답변2

실제 명령이 종료된 후 파이프 왼쪽의 stdout과 오른쪽의 stdin을 닫아 중단된 스크립트를 취소할 수 있습니다.

예:

#! /bin/dash
rm -f /tmp/s1 /tmp/s2
mkfifo /tmp/s1 /tmp/s2
{ (echo yes; exit 13); s1=$?; exec >&-; echo $s1 >/tmp/s1 & } | { (cat; exit 17); s2=$?; exec <&-; echo $s2 >/tmp/s2 & }
echo "`cat /tmp/s1` `cat /tmp/s2`"

(...; exit ..)해당 명령으로 바꾸십시오 .

실제 명령이 종료된 후 파이프 오른쪽의 stdin을 닫으면 오른쪽에서 명령을 파이프하려고 시도하는 동안 차단 대신 왼쪽의 write()가 SIGPIPE 또는 EPIPE를 수신하게 됩니다(이 자체는 open()에서 차단됩니다.) ), 그리고 왼쪽의 stdout을 닫으면 echo ... >fifo &왼쪽의 차단에서 파이프를 시도하는 대신 파이프 오른쪽의 read()가 EOF를 수신하게 됩니다 .echo ... >fifo &

수정해주신 @ilkkachu님께 감사드립니다.

관련 정보