두 개의 명령을 명명된 파이프로 전송할 때 경주

두 개의 명령을 명명된 파이프로 전송할 때 경주

여러 소스에서 데이터를 수신하는 명명된 파이프에서 데이터를 읽는 프로세스를 갖고 싶습니다.

$ mkfifo /tmp/p

하지만 지속적으로 작동하게 만드는 방법을 모르겠습니다.

첫 번째 시나리오 - 작동합니다

터미널 1:

내 fifo에 쓰기 위해 두 가지 프로세스를 설정합니다.

$ echo 'first' > /tmp/p; echo 'second' > /tmp/p

터미널 2:

파이프에서 읽기:

$ cat /tmp/p
first
second

위의 작업을 역순으로 수행해도 여전히 작동합니다.

내 문제는 파이프에서 두 개의 별도 명령을 실행하려고 할 때 발생합니다.

두 번째 경우 - 작동하지 않음

First.sh

#!/bin/sh
echo 'first' > /tmp/p

두 번째.sh

#!/bin/sh
echo 'second' > /tmp/p

터미널 1

$ sh first.sh; sh second.sh

터미널 2

$ cat /tmp/p
first

첫 번째 tty의 실행은 sh second.sh명명된 파이프에서 다른 항목을 읽을 때까지 무기한 차단됩니다.

내 생각엔 무슨 일이 일어나고 있는 것 같아?

~에서http://linux.die.net/man/7/pipe:

파이프의 쓰기 끝을 참조하는 모든 파일 설명자가 닫힌 경우 파이프에서 read(2)를 시도하면 파일 끝이 표시됩니다(read(2)는 0을 반환함).

따라서 echo종료할 때 first.sh이를 실행하는 셸이 파일 설명자를 닫습니다 . 이는 두 번째 TTY에 EOF가 표시된다는 /tmp/p의미입니다 .cat

쉘을 사용하여 이 문제를 어떻게 해결할 수 있습니까? 서브셸이 종료될 때 파이프가 닫히지 않도록 기본 제어 스크립트에서 명명된 파이프의 읽기 끝 부분에 대한 참조를 유지하는 방법이 있습니까? 실제로 저는 명명된 파이프의 경로를 서브셸에 전달합니다. 내 하위 쉘을 자체 표준 출력으로 출력하고 리디렉션해야 합니까?

여기에 뭔가 빠진 것 같은 느낌이 듭니다. 이 예제를 제외하고는 명명된 파이프를 사용하는 것이 내가 시도한 모든 작업에서 간단했습니다.

답변1

그냥 하면 안되는 이유:

{ echo foo; echo bar;} > /tmp/p

제어 스크립트가 파이프를 열린 상태로 유지하도록 하려면 다음을 수행할 수 있습니다.

exec 3<> /tmp/p

읽기-쓰기 모드로 명명된 파이프를 여는 것은 파이프가 아직 열려 있지 않은 동안 차단을 방지하는 것입니다. 아직 인스턴스가 없으면 인스턴스화합니다. 최소한 Linux에서는 작동하지만 POSIX에서는 작동을 보장하지 않습니다.

또는 (그리고 이식 가능):

: < /tmp/p & exec 3> /tmp/p

그런 다음 각 프로세스가 명명된 파이프를 열도록 하는 대신 다음을 수행할 수도 있습니다.

cmd >&3

마지막으로 다음을 수행합니다.

exec 3>&-

독자에게 그것이 완료되었음을 알리기 위해 글을 마무리합니다.

반대 논리를 원한다면 모든 s를 s <로 , s를 s로 변경하세요.><>

답변2

발견한 대로 cat을 사용하여 명명된 파이프에서 데이터를 읽을 수는 없습니다. 나는 몇 년 전에 똑같은 문제를 겪었고 다음과 같이 썼습니다.PCAT이 한계를 극복하기 위해.

답변3

당신은 고양이가 어떻게 작동하는지 오해했습니다. echo를 종료하면 cat도 종료됩니다. 따라서 쓰기 프로세스에서 rw 파이프를 열도록 강제할 수 없는 경우(그리고 열린 상태로 유지) 루프에서 cat을 호출하면 됩니다.

while true; do cat /tmp/p || break; done

예를 들어 ^C 등을 사용하여 cat을 취소하면 break가 활성화됩니다.

답변4

fifo의 읽기 측이 첫 번째 읽기 후에 닫히지 않도록 수동으로 fifo에 대한 더미 쓰기 참조를 열린 상태로 유지할 수 있습니다( tail -f /dev/null 1>fifo또는 사용).cat fifo 3>fifo

# tty1
bash -c '
mkfifo fifo || exit 1
tail -f /dev/null 1>fifo &
#0<&- cat fifo 3>fifo &
#lsof -p $!
echo first > fifo
echo second > fifo
kill $!
'

# tty2
cat fifo

관련 정보