Cygwin에서 파이프로 리디렉션할 때 /dev/stderr이 유효하지 않은 이유는 무엇입니까?

Cygwin에서 파이프로 리디렉션할 때 /dev/stderr이 유효하지 않은 이유는 무엇입니까?

/dev/stderr나는 최근에 최신 cygwin에서는 작동하지 않지만 성숙한 데비안 설치에도 존재하는 놀라운 문제를 발견했습니다 . (편집: 내 초기 생각과는 달리 내 Debian 시스템은 이 오류를 노출하지 않고 단순히 원하는 출력을 생성합니다. 지금은 이것이 cygwin 버그라고 가정해야 합니다.)

배경: 저는 수천 줄의 출력을 생성할 수 있는 도구(특히 대규모 생산 시스템의 버전 ​​제어 시스템)를 사용하여 작업합니다. 스크립트 제어를 통해 실행 중이며 시끄러운 도구 출력을 로그 파일로 리디렉션하는 옵션을 원합니다. 간단한 해결책은 항상 (stderr 및 stdout) 출력을 환경 변수에 저장된 파일 시스템 대상으로 리디렉션하는 것 같습니다. 터미널(또는 일부 사용자 제어 대상)에 출력이 필요한 경우 대상은 DBG_STDERR"/dev/stderr"일 뿐이고 그렇지 않은 경우 임시 파일 이름입니다. 일반적인 도구 실행 라인은 다음과 같습니다 noisy_command >> "$DBG_STDERR" 2>&1.

스크립트의 출력을 파이프하지 않으면 잘 작동합니다. 최소한의 표현은 다음과 같습니다.

$ uname -a
CYGWIN_NT-6.1-WOW xxxxxxx 2.8.1(0.312/5/3) 2017-07-03 14:06 i686 Cygwin

$ bash --version
GNU bash, version 4.4.12(3)-release (i686-pc-cygwin)

$ cat say-something.sh
#!/bin/sh
echo something > /dev/stderr

$ (x=$(./say-something.sh 2> /dev/stderr)) 2>&1 |cat
./say-something.sh: line 2: /dev/stderr: No such file or directory

$ (x=$(./say-something.sh 2> /dev/stderr)) 2>&1
something

$ (x=$(./say-something.sh 2> /dev/stderr))  |cat
something

$ x=$(./say-something.sh 2> /dev/stderr) 2>&1 |cat
something

물론 모든 리디렉션과 중첩된 쉘은 문맥에 맞지 않게 이상해 보입니다. say-something.sh가 실제로 다른 스크립트에 의해 호출되기 때문에 추가 셸이 필요합니다. fd 2에서 stderr로의 중복 리디렉션은 파일(/dev/stderr 또는 실제로 구성 가능한 변수 내용인 다른 경로)로의 선택적 리디렉션을 위한 편리한 "스위치"입니다.

실패한 예에 따른 실험에서 알 수 있듯이 이 파이프라인의 모든 구성 요소가 필요한 것 같습니다. 모두 성공합니다.

  • 표준 출력의 마지막 파이프가 필요합니다
  • stderr를 stdout으로 복사하려면 호출자가 필요합니다.
  • 명령 대체 쉘이 필요합니다.

답변1

/dev/stderr이름은 파이프로 리디렉션할 때 실제로 유효합니다. 불가능할 수도 있는 것은 /dev/stderr최종 목표를 직접 여는 것입니다. 다음을 살펴보세요:

$ (echo Testing testing > /dev/stderr) |& cat
Testing testing

||&에 의해 생성되거나 일반적으로 파이프는익명 파이프;표시된 이름파일 시스템의 개체와 일치하지 않습니다.. 예를 들어 다음과 같은 간단한 것을 시도해 볼 수 있습니다.

$ ls -la /dev/fd/ |& cat
total 0
dr-x------ 2 alexp alexp  0 Jul  6 18:23 .
dr-xr-xr-x 9 alexp alexp  0 Jul  6 18:23 ..
lrwx------ 1 alexp alexp 64 Jul  6 18:23 0 -> /dev/pts/4
l-wx------ 1 alexp alexp 64 Jul  6 18:23 1 -> pipe:[1058859]
l-wx------ 1 alexp alexp 64 Jul  6 18:23 2 -> pipe:[1058859]
lr-x------ 1 alexp alexp 64 Jul  6 18:23 3 -> /proc/4335/fd

열려고 하는 (최종) 대상의 /dev/stderr이름은 매우 /dev/stderr특이 합니다.피하다실제 목표를 찾기 위해 노력하십시오.

답변2

문제는 결과적으로 읽는 과정에 있다고 생각합니다. 프로세스가 중지되면 닫히는 자체 리디렉션 파이프가 있습니다(얻는 pid는 셸의 pid가 아니라 readlink 프로세스의 pid입니다). 프로세스가 종료되면 파이프가 유효하지 않게 됩니다. fifos/namedpipe를 사용해 보세요.

관련 정보