파이프를 통해 꼬리에 명령 보내기: 첫 번째 명령은 언제 중단됩니까?

파이프를 통해 꼬리에 명령 보내기: 첫 번째 명령은 언제 중단됩니까?

이 예에서는 다음과 같습니다.

$ for i in {1..3}; do sleep 1; echo $i;  done | head -n 2

첫 번째 명령(for 루프) 3이 표시 직전에 종료되는 이유는 무엇입니까? 나는 그것이 2보여지자마자 죽임을 당할 것이라고 예상했다.

처음에 해결하려고 했던 문제는 다음과 같습니다.

$ for i in *(/); do c=`find "$i" -iname "*.ext" | wc -l`; echo "$c  $i"; done | head -n 3

화면에 3줄이 뜨면 바로 끝날 줄 알았는데, 4번 루프를 돌면서 4번째 줄을 버렸습니다.

내가 일어날 것이라고 생각한 일 :

sleep 1
echo 1
sleep 1
echo 2 
# 2 is printed and the for loop is killed

실제로 일어난 일:

sleep 1
echo 1
sleep 1
echo 2 
sleep 1
echo 3
# 3 is not printed and the for loop is killed

루프 자체 내부에 일부 논리를 추가하지 않고 지정된 반복 횟수 후에 루프를 즉시 중단하는 방법이 있습니까?

답변1

내 다른 쉘(ksh, zsh, bash)에는 예상되는 동작이 있습니다. 3이 아닌 1, 2만 있습니다. 여기서 문제는 ZSH 버전에서 SIGPIPE가 처리되는 방식과 관련이 있을 수 있습니다.

"환경이 없는" 인스턴스를 사용하여 이러한 명령을 실행해 볼 수 있습니까? 예를 들어 별칭, 구성 등이 없습니다.

주석에서 말했듯이, 쉘이 write() 함수를 사용하여 무언가를 에코하려고 하면 오류가 발생합니다. 전체 파이프라인 체인이 실행 중인 한(프로세스 head는 계속 실행 중이고 STDIN은 열려 있음) 모든 것이 정상입니다. 그러나 head종료되면 쉘의 출력은 아무데도 가지 않습니다(깨진 파이프).

그러나 쉘이 표준 출력에 무언가를 쓰려고 시도할 때까지 파이프가 끊어진 것을 모르고 처리를 계속합니다.

따라서 디버그에 "echo 3"이 표시되며 이는 실패하고 셸을 종료합니다.

답변2

SIGPIPE는 프로그램이 닫힌 파이프에 쓰려고 할 때만 전송됩니다. 그렇지 않은 경우 SIGPIPE를 보내는 것은 매우 나쁩니다. 파이프를 여는 프로그램은 이에 대해 알지도 못할 수 있으며 파이프와 상호 작용하지 않더라도 종료되어서는 안 됩니다.

에서는 for i in 1 2 3; do sleep 1; echo $i; done명령 sleep이 아무 것도 쓰지 않으므로 신호를 수신하지 않습니다. echoSIGPIPE는 실행될 때만 전송됩니다 .

일반적으로 SIGPIPE는 정밀 작업용으로 설계되지 않았습니다. 출력 생성을 담당하는 프로그램이 출력 소비자가 떠난 후에도 계속 실행되지 않도록 하기 위한 것입니다. 대부분의 실제 사례에서 파이프 왼쪽에 있는 프로그램은 쓰기를 버퍼링하고 다음에 버퍼가 플러시될 때만 SIGPIPE를 수신합니다.

여러 번 반복한 후 루프를 중지하려면 해당 논리를 루프에 구축하세요.

관련 정보