popen 및 JS ffi에서 파이프 파손 오류가 발생합니다.

popen 및 JS ffi에서 파이프 파손 오류가 발생합니다.

나는페이페이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깨진 파이프는 실행이 중지되었기 때문에 버려집니다.trhead

두 시나리오 모두 나에게는 의미가 있지만 상호 배타적인 것 같습니다. 통화의 차이점이 무엇인지 이해하지 못합니다.

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시작되고 완료됩니다 .trhead

을 실행하면 strace -fe write다음과 같은 내용이 표시됩니다.

write(1, "AJiYTlFFjjVIzkhCAhccuZddwcydwIIw"..., 4096) = -1 EPIPE (Broken pipe)

writeSIGPIPE를 트리거하는 대신 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

관련 정보