
나는 최근 잘 성숙한 데비안 설치에도 존재하는/dev/stderr
최신 cygwin에서 유효하지 않은 놀라운 문제를 우연히 발견했습니다 . (편집: 내가 원래 생각했던 것과는 반대로 내 데비안 시스템은 이 오류를 노출하지 않고 단순히 원하는 출력을 생성합니다. 이제 이것이 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 또는 다른 경로는 실제로 구성 가능한 변수 내용)에 대한 선택적 리디렉션을 용이하게 하는 "스위치"입니다.
실패한 예제 이후의 실험에서 알 수 있듯이 이 파이프라인의 모든 구성 요소가 필요한 것처럼 보입니다. 모두 성공합니다.
- 우리는 stdout의 마지막 파이프가 필요합니다
- 호출자가 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
문제는 생성된 readline-process라고 생각합니다. 프로세스가 중지되면 닫히는 리디렉션을 위한 자체 파이프를 얻습니다(얻는 pid는 셸의 pid가 아니라 readlink-process의 pid입니다). 프로세스가 종료되면 파이프가 유효하지 않게 됩니다. fifos/named Pipe를 사용해 보세요.