Emacs 쉘(eshell)을 사용할 때 이 간단한 명령이 실패하는 이유는 무엇입니까?
cat file.txt | wc
10241줄을 포함하는 파일이 있습니다. 한 줄에 50자 미만입니다. 이 명령을 실행하면 약 90%의 시간 동안 행 개수와 같은 잘못된 결과가 나타납니다. 그래도 오류 메시지는 표시되지 않습니다.
파이프 파열이 흔한 주제인 것 같은데 합리적인 설명을 찾지 못했습니다. 게다가 누구도 해결 방법을 제시하지 못했습니다. 이 간단한 명령을 어떻게 안정적으로 작동시킬 수 있습니까?
물론 그냥 도망칠 수도 있다 wc file.txt
. 그러나 저는 모든 도구가 Piped cat: 에서 잘 작동하는 보다 일반적인 솔루션을 찾고 있습니다 cat file.txt | any_tool_here
.
세부 사항
CentOS 5를 사용하고 있습니다. 이 문제는 다음을 사용할 때 발생합니다.eshell (이맥스 쉘). 저는 GNU Emacs 24.5.2를 사용하고 있습니다.
실험
결과 예 cat file.txt | wc
(예상: 첫 번째 열은 항상 10241임)
- 8568 25706 110571
- 9837 29513 126947
- 5395 16187 69615
- 9202 27608 118757
- 7299 21899 94199
- 9837 29513 126947
다음을 사용한 결과 예 wc file.txt
:
- 10241 30723 132156
- 10241 30723 132156
- 10241 30723 132156
- 10241 30723 132156
- 10241 30723 132156
- 10241 30723 132156
cat 명령 자체는(혼자 실행될 때) 잘 작동합니다. 다음 명령을 사용하여 여러 번 확인했습니다 cat file.txt > file2.txt
. 그런 다음 두 파일을 비교했는데 동일합니다.
답변1
사용된 쉘( )에 대한 정보로 볼 때 eshell
, 해당 쉘의 스트림 처리 측면이 원인인 것으로 보입니다. 일반적으로 파이프는 파이프 + 포크/exec의 양쪽 끝을 여는 것을 의미하므로 파이프 파일 설명자를 공유하는 두 프로세스를 얻게 되며 통신은 커널을 통해 직접 진행됩니다. 이렇게 하면 아무것도 손실되지 않습니다. 안전이 보장됩니다(비록 관련 파이프나 스트림이 버퍼링된 경우 스트림의 마지막 청크를 플러시하기 전에 첫 번째 프로세스가 정상적으로 종료될 때까지 기다려야 할 수도 있습니다).
발췌로 판단하면전자 인클로저 브로셔:
Eshell은 bash 또는 zsh와 같은 시스템 쉘을 대체할 수 없습니다. Emacs와 외부 프로세스 간에 텍스트를 이동하려면 Eshell을 사용하십시오. 하나의 외부 프로세스에서 다른 프로세스로(그리고 다른 프로세스로) 출력을 파이프하려는 경우에는 시스템 쉘을 사용하십시오. 왜냐하면 Emacs의 IO 시스템은 버퍼-이기 때문입니다. 스트림 지향이 아닌 지향적이며 이러한 작업에서는 매우 비효율적입니다. Eshell에서 쉘 스크립트를 작성하려면 그렇게 하지 마십시오. elisp 라이브러리를 작성하거나 시스템 쉘을 사용하십시오.
일반적인 방법으로 이 작업을 수행하는 대신 eshell은 "버퍼"(열린 파일에 대한 emacs의 표현)를 데이터의 중간 저장소로 사용하여 파이프를 가짜로 만듭니다 wc
. read
, 버퍼를 채우기 위해 첫 번째 프로그램에서 추가 입력을 기다리는 대신 emacs
빈 블록으로 응답( read
스트림의 끝을 나타 내기 위해 0 반환)으로 끝납니다. 그렇다면 eshell은 비효율적일 뿐만 아니라 파이프를 다룰 때에도 결함이 있다는 뜻이다.