나는페이페이nodejs의 경우 이는 이 질문과 크게 관련이 없으며 실제로는 파이프라인을 더 잘 이해하는 것이지만 일부 컨텍스트를 제공합니다.
function exec(cmd) {
var buffer = new Buffer(32);
var result = '';
var fp = libc.popen('( ' + cmd + ') 2>&1', 'r');
var code;
if (!fp) throw new Error('execSync error: '+cmd);
while( !libc.feof(fp) ){
libc.fgets(buffer, 32, fp)
result += buffer.readCString();
}
code = libc.pclose(fp) >> 8;
return {
stdout: result,
code: code
};
}
이 exec 함수를 사용하여 실행하면 이 코드가 표시됩니다.
tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8}
오류가 발생합니다.
write error: Broken pipe
tr: write error
하지만 예상했던 결과가 나왔습니다. 즉, 8개의 난수입니다. 이것이 나를 혼란스럽게 만들었지만, 광적인 인터넷 검색 중에 나는 발견했습니다.이것스택 답변은 내 경우에 완벽하게 작동합니다.
하지만 여전히 몇 가지 질문이 있습니다.
왜:
tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8}
내 exec 명령을 호출하면 깨진 파이프 오류가 발생하지만 셸에서 호출하면 그렇지 않습니까? 왜 전화했는지 이해가 안 돼요:
tr -dc "[:alpha:]" < /dev/urandom
끝없이 읽히지만 파이프로 연결하면 다음과 같습니다.
head -c ${1-8}
깨진 파이프 오류가 발생하지 않고 잘 작동합니다. 이 내용을 읽으려면 head
시간이 많이 걸리고 tr
영원히 걸릴 것 같습니다 . 최소한 깨진 파이프는 버려야 합니다. head
처음 8바이트가 소비된 후에도 출력은 계속 인쇄되고 tr
깨진 파이프는 실행이 중지되었기 때문에 버려집니다.tr
head
두 시나리오 모두 나에게는 의미가 있지만 상호 배타적인 것 같습니다. 통화의 차이점이 무엇인지 이해하지 못합니다.
exec(tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8})
그리고
tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8}
명령줄에서 직접, 특히 <
무한한 파일이 어떤 것으로 이동한 다음 |
다른 것으로 이동하여 끝없이 실행되지 않는 이유는 무엇입니까? 나는 수년간 이 일을 해왔지만 왜 이런 일이 일어났는지 의문을 품은 적이 없습니다.
마지막으로, 이 깨진 파이프 오류를 무시할 수 있습니까? 해결 방법이 있나요? 내 C++ ish 자바스크립트 코드에 뭔가 문제가 있는 걸까요? 나는 몇 가지 대중적인 기본 사항을 놓치고 있습니까?
- - - 편집하다
일부 코드를 어지럽히다
exec('head -10 /dev/urandom | tr -dc "[:alpha:]" | head -c 8')
파이프라인 오류가 발생하지 않습니다!
답변1
일반적 tr
으로 head
.
tr
실행 중인 프로세스가 SIGPIPE를 무시하도록 구성되었기 때문에 해당 오류 메시지가 표시됩니다 . 나는 이것이 popen()
당신의 언어로 구현함으로써 이루어질 수 있다고 생각합니다.
다음을 수행하여 재현할 수 있습니다.
sh -c 'trap "" PIPE; tr -dc "[:alpha:]" < /dev/urandom | head -c 8'
다음을 수행하여 무슨 일이 일어나고 있는지 확인할 수 있습니다.
strace -fe signal sh your-program
(또는 Linux를 사용하지 않는 경우 시스템에서 이에 상응하는 것). 그러면 다음과 같은 내용이 표시됩니다.
rt_sigaction(SIGPIPE, {SIG_IGN, ~[RTMIN RT_1], SA_RESTORER, 0x37cfc324f0}, NULL, 8) = 0
또는
signal(SIGPIPE, SIG_IGN)
명령줄은 동일한 프로세스나 그 하위 프로세스 중 하나에서 실행되며 이전 프로세스에서 /bin/sh
시작되고 완료됩니다 .tr
head
을 실행하면 strace -fe write
다음과 같은 내용이 표시됩니다.
write(1, "AJiYTlFFjjVIzkhCAhccuZddwcydwIIw"..., 4096) = -1 EPIPE (Broken pipe)
write
SIGPIPE를 트리거하는 대신 EPIPE 오류로 인해 시스템 호출이 실패합니다.
어쨌든 종료됩니다 tr
. SIGPIPE가 무시되는 경우(그러나 이로 인해 오류 메시지도 트리거됨) 그렇지 않은 경우 SIGPIPE를 받은 후 종료합니다. /dev/urandom
이 8바이트 이후에는 read
계속해서 읽는 것을 원하지 않기 때문에 종료하기를 원합니다 head
.
이 오류 메시지를 방지하려면 다음 명령을 사용하여 SIGPIPE에 대한 기본 핸들러를 복원할 수 있습니다.
trap - PIPE
전화하기 전에 tr
:
popen("trap - PIPE; { tr ... | head -c 8; } 2>&1", ...)
답변2
이것은 나에게도 효과적입니다. 오류 메시지를 표시하지 않으려면 tr을 추가하세요 2>/dev/null
.
tr -dc "[:alpha:]" < /dev/urandom 2>/dev/null | head -c 8