저는 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 오류가 발생할 수 있습니다.
제가 하려는 일은 불가능하다고 생각합니다. 내 응용 프로그램은 "동시에 읽고 쓸 수 없습니다". 파이프의 양쪽을 열어두는 중간 프로그램을 만들어야 할 것 같습니다.