파이프에 문제가 있습니다. 읽기가 완료된 후 파이프가 종료됩니다.

파이프에 문제가 있습니다. 읽기가 완료된 후 파이프가 종료됩니다.

저는 OSX를 사용하고 있으며 bash를 사용하고 있으며 파이프를 이해하려고 노력하고 있습니다. 나는 프로그램이 bash 쉘과 양방향으로 통신하도록 하고 싶습니다. 항상 동일한 쉘이 되도록 설정하여 디렉토리로 이동하면 bash가 이를 기억할 수 있습니다(항상 새로운 bash 쉘을 사용하는 대신).

내가 지금까지 시도한 것은 이것이다. 새 터미널(A)에서 실행

mkdir /tmp/IOdir
cd /tmp/IOdir
mkfifo pToB
mkfifo bToP
tail -f -1 pToB | bash >> bToP

그런 다음 이 연결을 테스트하기 위해 새 터미널(B)에서 시작할 수 있습니다.

cd /tmp/IOdir
echo echo hello > pToB

제3터미널(C)에서 출발

cd /tmp/IOdir
(read myline &&  echo $myline) < bToP

이것이 내가 원하는 행동이다. 동일한 bash 쉘은 활성 상태로 유지되며 출력은 다른 쪽 끝을 통해 제공됩니다. 나중에 참조할 수 있도록 이 상황을 X라고 부르세요.

상태 X에서 계속

그러나 이제 이 X 상태부터는 더 이상 같은 일을 할 수 없습니다. 즉, 터미널 (B)에서 수행하면

echo echo hello > pToB

그런 다음 터미널 C에서

(read myline &&  echo $myline) < bToP

그런 다음 터미널 C에서는 아무것도 들어오지 않았습니다. 그리고 또 이렇게 하면 터미널 B에서

echo echo hello > pToB

Bash 쉘이 닫힙니다.

상태 X에서 할 수 있는 일은 먼저 터미널 C에서 하는 것입니다.

(read myline &&  echo $myline) < bToP

그런 다음 터미널 B에서 출발하세요.

echo echo hello > pToB

이 경우 터미널 C는 hello 신호를 내보내고 다시 상태 X에 있는 것처럼 보입니다. 그래서 우리는 기본적으로 이것을 영원히 반복할 수 있습니다. 이제 이것은 양방향 통신에 충분해 보이지만 내 프로그램은 다음과 같은 새 라인을 요청하는 경우 이렇습니다.

(read myline &&  echo $myline)

그리고 새 줄이 없으면 "정지"됩니다(bash와 마찬가지로 실제로 프로그램에서 bash 호출을 사용한다는 의미입니다). 따라서 이후에는 입력을 pToB로 보낼 ​​수 없으며 제가 할 수 있는 일은 없습니다.

질문

C 프로그래밍을 너무 많이 사용하지 않고 이를 설정할 수 있는 방법이 있습니까? 두 개의 명명된 파이프를 사용하지 않고 이 작업을 더 우아하게 수행할 수 있는 방법이 있습니까? 어떤 경우에는 파이프가 닫히지만 다른 경우에는 닫히지 않는 원인은 무엇입니까?

편집하다

~에서Wikipedia의 이 페이지, 우리는

전이중(양방향) 통신에는 일반적으로 두 개의 익명 파이프가 필요합니다.

한편으로는 적어도 파이프 수가 정확한 것 같습니다. 반면에 익명 파이프가 아닌 명명된 파이프를 사용합니다. 그래서 아마도 어려울 수도 있고 불가능할 수도 있습니다.

또한 mkfifoGNU/리눅스 소스 코드아마도 mknod에 따라 정의되었을 것입니다.GNU/리눅스 소스 코드, 이는 유닉스 명령이기도 합니다. 그러나 나는 그것으로부터 배울 것이 많지 않다고 확신합니다.

여기파이프라인의 Linux 소스 코드를 포함하여 C 언어 파이프라인에 대한 소개입니다. 실제로 이런 일이 발생한다면 파이프가 닫힌 이유를 알 수 있을 것입니다.

여기fifo가 닫히는 것을 방지하는 것과 관련된 질문입니다. 답변에서 했던 것처럼 백그라운드 수면 프로세스에 파이프를 연결하려고 시도했지만 도움이 되지 않았습니다.

답변1

이유는 를 이용하세요 strace.

tail -f | strace bash >> foo

두 번째 사람은 echo echo hello > pToB나에게 이렇게 말했습니다.

rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
read(0, "e", 1)                         = 1
read(0, "c", 1)                         = 1
read(0, "h", 1)                         = 1
read(0, "o", 1)                         = 1
read(0, " ", 1)                         = 1
read(0, "h", 1)                         = 1
read(0, "e", 1)                         = 1
read(0, "l", 1)                         = 1
read(0, "l", 1)                         = 1
read(0, "o", 1)                         = 1
read(0, "\n", 1)                        = 1
write(1, "hello\n", 6)                  = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=3299, si_uid=1000} ---
+++ killed by SIGPIPE +++

따라서 두 번째로 hello\n을 작성하려고 하면 깨진 파이프 오류가 발생하므로 hello를 읽을 수 없고(작성된 적이 없음) bash가 종료됩니다.

파이프를 열어두려면 뭔가를 사용해야 할 것 같아요.

이건 어때?

(while read myline; do echo $myline; done) < pToP

man 7 pipe관련된 추가 배경 정보를 보려면 파이프 주변의 다양한 오류 조건을 설명합니다.

답변2

Frostschutz의 답변에 대한 부록으로 다음 표를 고려하십시오.

여기에 이미지 설명을 입력하세요.

처음으로 bToP에 hello를 보내려고 하면 fifo 리더가 있을 때까지 차단됩니다. 두 번째로 리더는 Bash를 종료하는 SIGPIPE 신호를 다시 보냅니다. 이를 무시하더라도 나중에 EPIPE 오류가 발생할 수 있습니다.

제가 하려는 일은 불가능하다고 생각합니다. 내 응용 프로그램은 "동시에 읽고 쓸 수 없습니다". 파이프의 양쪽을 열어두는 중간 프로그램을 만들어야 할 것 같습니다.

관련 정보