명명 된 파이프, 파일 설명자 및 EOF


10

bash 프롬프트가있는 동일한 사용자의 두 창 창 1에서 다음을 입력하십시오.

$ mkfifo f; exec <f

따라서 bash는 이제 파일 디스크립터 0에서 이름을 가진 pipe에 맵핑하려고합니다 f. 창 2에서 다음을 입력하십시오.

$ echo ls > f

이제 window-1은 ls를 인쇄하고 쉘은 죽습니다. 왜?

다음 실험 :로 window-1을 다시 엽니 다 exec <f. 창 2에서 다음을 입력하십시오.

$ exec 3>f
$ echo ls >&3

위의 첫 번째 줄 이후에, window-1이 깨어나고 프롬프트를 인쇄합니다. 왜? 위의 두 번째 줄 이후에 window-1은 ls출력을 인쇄 하고 쉘은 활성 상태를 유지합니다. 왜? 실제로, 이제는 window-2 echo ls > f에서 window-1 쉘을 닫지 않습니다.

대답은 명명 된 파이프를 참조하는 창 2의 파일 설명자 3 의 존재 와 관련이 있어야합니까 ?!


1
exec <f, bash시도되지 않은 읽기 에서 f, 처음 시도하는 을. 는 open()파이프에 기록 모드로 다른 오픈 (되는 파이프가 인스턴스화 될 가리키고 쉘이 입력을 판독한다)하고 어떤 프로세스가있을 때까지 복귀하지 않을 것이다.
Stéphane Chazelas 2016 년

@ StéphaneChazelas. 이것이 일단 exec 3>f실행되면 첫 번째 쉘이 프롬프트를 표시하는 이유 입니다. (사소한 점, 귀하의 의견에서 " 쓰기 모드" 를 의미 했 습니까?)
Fixee

1
맞아 미안해. 5 분 기한 직전의 편집
Stéphane Chazelas

답변:


12

그것은 함께 할 수있다 닫는 파일 기술자의.

첫 번째 예제에서는 echo을 연결하기 위해 셸이 여는 표준 출력 스트림에 씁니다. f종료되면 셸에서 디스크립터가 닫힙니다. 수신 측에서 표준 입력 스트림 (에 연결된 f) 에서 입력을 읽는 쉘은 표준 입력 의 파일 끝 조건으로 인해 ls실행 된 ls다음 종료됩니다.

파일 끝 조건은 명명 된 파이프 (이 예제에서는 오직 하나)에 대한 모든 작성자가 파이프의 끝을 닫았 기 때문에 발생합니다.

두 번째 예에서는 exec 3>f에 쓰기 위해 파일 설명자 3을 연 f다음 echo씁니다 ls. echo명령이 아닌 파일 디스크립터가 열린 쉘입니다 . 디스크립터는 사용자가 할 때까지 열려 있습니다 exec 3>&-. 수신 측에서 표준 입력 스트림 (에 연결된 f) 에서 입력을 읽는 쉘 은 read ls를 실행 ls한 다음 더 많은 입력을 기다립니다 (스트림이 여전히 열려 있기 때문에).

스트림에 대한 모든 작성자 (쉘, via exec 3>fecho)가 파이프의 끝을 닫지 않았 으므로 스트림은 열린 상태로 유지됩니다 ( exec 3>f아직 유효).


나는 echo그것이 외부 명령 인 것처럼 위에서 언급했습니다. 쉘에 내장되었을 가능성이 높습니다. 그럼에도 불구하고 효과는 같습니다.


6

그다지 많지 않습니다. 파이프에 작가가 없을 때 독자에게 가까워 보입니다. 즉 읽을 때 EOF를 반환하고 열 때 차단합니다.

Linux 매뉴얼 페이지에서 ( pipe(7)참조 fifo(7)) :

파이프의 쓰기 끝을 참조하는 모든 파일 디스크립터가 닫히면 read(2)파이프에서 시도하면 파일 끝이 표시됩니다 ( read(2)0이 리턴 됨).

쓰기 끝을 닫는 것은의 끝에서 내재적으로 발생 echo ls >f하는 것이며 다른 경우 파일 설명자는 열린 상태로 유지됩니다.


Java (및 기타 OO 언어)의 참조 횟수와 비슷한 것으로 보입니다! 그래도 말이됩니다.
Fixee

2

@ Kusalananda와 @ikkachu의 두 가지 대답을 읽은 후에 이해합니다. window-1에서 쉘은 파이프의 쓰기 끝을 열고 닫을 무언가를 기다리고 있습니다. 쓰기 끝이 열리면 window-1의 쉘이 프롬프트를 인쇄합니다. 쓰기 끝이 닫히면 쉘은 EOF를 받고 죽습니다.

첫 번째 상황에 : 윈도우-2면에서 우리는 두 가지 상황이 내 질문에 설명이 echo ls > f거기에 우리가있다, 그래서 어떤 파일 기술자 (3), 없다, echo그 산란과 stdinstdout모양이 같은 :

0 --> tty
1 --> f

그런 다음 echo종료하고 셸은 두 설명자를 모두 닫습니다. 파일 디스크립터 1이 닫히고 참조되기 때문에 f쓰기 끝 f이 닫히고 EOF가 window-1이됩니다.

두 번째 상황에서는 exec 3>f쉘에서 실행 하여 쉘이이 환경을 사용하게합니다.

bash:
0 --> tty
1 --> tty
2 --> tty
3 --> f

이제 우리는 실행 echo ls >& 3하고 쉘 echo은 다음과 같이 파일 디스크립터를 할당합니다 :

echo:
0 --> tty
1 --> f     # because 3 points to f
2 --> tty

그런 다음 쉘은를 포함하여 위의 세 가지 설명자를 닫지 ff여전히 쉘 자체에서 이에 대한 참조를 갖습니다. 이것이 중요한 차이점입니다. exec 3>&-@Kusalananda가 지적한 것처럼 설명자 3을 닫으면 마지막으로 열린 참조가 닫히고 EOF가 window-1이됩니다.


이것은 처음 세 파일 디스크립터를 수정해야 할 적절한 설계 이유가없는 한, 파일 디스크립터를 그대로 두어야하는 이유에 대한 좋은 예입니다. 다른 쉘에 대한 입력 디스크립터 (0) 인 디스크립터 (1)를 사용한 경우 파이프 (및 해당 특정 데이터 스트림으로 수행 한 작업)를 닫을뿐만 아니라 두 번째에 대한 입력도 닫았습니다. 쉘이 종료되었습니다. 이것은 괜찮지 만 의도적으로 수행하는 경우에만 가능합니다. 더 높은 번호의 파일 디스크립터를 사용하면 이와 같은 부작용을 피할 수 있습니다. 왜냐하면 어떤 특정 상태에 있거나 정의되어 있지도 않기 때문입니다.
Joe

솔직히 말해서, 나는 그 의견에서 무엇을 말하려고했는지 잘 모르겠습니다. 그냥 삭제하겠습니다.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.