필터를 통해 STDERR 만 파이프하십시오.


82

bash에서 STDOUT과 통합하기 전에 필터를 통해 STDERR을 파이프하는 방법이 있습니까? 즉, 나는 원한다

STDOUT ────────────────┐
                       ├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘

보다는

STDOUT ────┐
           ├────[ filter ]───> terminal/file/whatever
STDERR ────┘

답변:


64

다음 은 bash에서 파일 설명자를 교체하는 방법을 모델로 한 예제 입니다. a.out의 출력은 'STDXXX :'접두사가없는 다음과 같습니다.

STDERR: stderr output
STDOUT: more regular

./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
more regular
stdErr output

위 링크에서 인용 :

  1. 먼저 표준 출력을 & 3으로 저장합니다 (& 1은 3으로 속임)
  2. 다음으로 stdout을 stderr로 보냅니다 (& 2는 1로 속임)
  3. stderr을 & 3 (stdout)으로 전송 (& 3은 2로 속임)
  4. 닫기 & ​​3 (&-는 3으로 속임)

1
나를 위해 작동하지 않습니다. 마지막으로 3>&2 2>&1 1>&3-.
aleung

3
주의 : 이것은 FD 3이 사용되지 않는다고 가정하고 파일 설명자 1과 2의 스와핑을 실행 취소하지 않으므로이 명령을 다른 명령으로 계속 파이프 할 수 없습니다. 자세한 내용과 해결 방법 은 이 답변 을 참조하십시오 . {ba, z} sh에 대한 훨씬 더 깨끗한 구문은 이 답변을 참조하십시오 .
Tom Hale

24

프로세스 대체의 순진한 사용은 다음과 stderr별도로 필터링을 허용하는 것 같습니다 stdout.

:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err

참고 stderr에 나오는 stderrstdoutstdout우리가 또 다른 서브 쉘에서 전체를 감싸고 파일로 리디렉션으로 볼 수있는, o그리고e

( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e

왜 :; 처음에? 나는없이 매직 라인을 시도했지만 차이를 만들지 않는 것 같습니다.
Koshmaar

1
어떤 사람들 $은 명령 프롬프트로 사용 합니다. 그런 다음 종종 다음과 같은 쉘 예제를 작성 $ cat /var/log/syslog | fgrep ...합니다.. 그러나이 줄은 $. :;프롬프트처럼 보이지만 기본적으로 쉘이 작동하지 않습니다. 전체 라인을 안전하게 선택하여 붙여 넣을 수 있습니다.
solidsnack

23
좋아요,하지만 그냥 생략 할 수 있습니다 :; 그리고 줄은 또한 복사-붙여 넣기 가능합니다. :) 나에게 :; 프롬프트처럼 보이지 않고 예제를 더 명확하게 (출력에서 명령 분리) 만들지는 않았지만 혼란 스러웠습니다. 귀하의 관점을 이해하고 구문 / 관습에 대해 논의하지 않겠습니다.
Koshmaar

24

TL; DR :

$ cmd 2> >(stderr-filter >&2)

예:

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%

이것은 bash와 zsh에서 모두 작동합니다. Bash는 요즘 거의 유비쿼터스이지만 POSIX sh에 대한 (정말로 형편없는) 솔루션이 정말로 필요하다면 여기참조하십시오 .


설명

지금까지 가장 쉬운 방법은 프로세스 대체 를 통해 STDERR을 리디렉션하는 것입니다 .

프로세스 대체를 사용하면 프로세스의 입력 또는 출력을 파일 이름을 사용하여 참조 할 수 있습니다. 형태는 다음과 같습니다.

>(list)

프로세스 목록은 비동기 적으로 실행되며 입력 또는 출력은 파일 이름으로 나타납니다.

따라서 프로세스 대체로 얻는 것은 파일 이름입니다.

당신이 할 수있는 것처럼 :

$ cmd 2> filename

넌 할 수있어

$ cmd 2> >(filter >&2)

>&2리디렉션의 filter원래 STDERR에의 STDOUT 백.


1
이 답변에 대한 경고가 있습니다. bash 는 대체 프로세스가 완료 될 때까지 기다리지 않는 반면 FD는 1과 2를 스왑하기 위해 저글링합니다. 이것은 중요 할 수 있습니다. 나는 이것이 exec 2> >(while .. read .. echo)systemd 서비스로 실행되는 스크립트에서 불타 버렸다 . journald는 서비스의 fd2를 캡처하고 '<N>'접두사에서 로그 수준을 유추합니다. <2> 출력 줄 앞에 추가 하면 저널 레코드에 ERROR 수준이 할당됩니다. 그러나 때때로 systemd는 가장 중요한 메시지 인 마지막 메시지를 기록하기 전에 메인 프로세스 그룹을 종료 할 때 전체 프로세스 그룹을 더 빨리 종료했습니다!
kkm

좋은 간단한 해결책. 주의 : 크론 작업의 일부로 이것을 사용하는 데주의하십시오. cron이 사용하는 일부 쉘에서는 프로세스 대체를 사용할 수 없습니다.
Quinn Comendant

15

요약 : (bash 및 zsh)

$ cmd 2> >(stderr-filter >&2)

예:

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%

StackExchange 네트워크에 대한 많은 답변의 형식은 다음과 같습니다.

cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'

여기에는 내장 된 가정이 있습니다. 파일 설명자 3은 다른 용도로 사용되지 않습니다.

대신 명명 된 파일 설명자를 사용하고 사용 {ba,z}sh가능한 다음 파일 설명자> = 10을 할당합니다.

cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'

명명 된 파일 설명자는 POSIX에서 지원되지 않습니다 sh.

위의 다른 문제는 STDOUT 및 STDERR을 원래 값으로 다시 바꾸지 않고는 명령을 추가 명령으로 파이프 할 수 없다는 것입니다.

POSIX에서 진행되는 파이핑을 허용하려면 sh(그리고 여전히 FD 3이 사용되지 않는다고 가정) 복잡해집니다 .

(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1

따라서 이것에 대한 가정과 문법을 감안할 때 위의 TL; DR에 표시된 더 간단한 bash/ zsh구문을 사용하는 것이 더 나을 입니다.


8

bash 프로세스 대체의 사용은 원래 의도를 거의 그대로 반영하므로 기억하고 사용하기가 더 쉽습니다. 예를 들면 :

$ cat ./p
echo stdout
echo stderr >&2
$ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/'
sTdout
STderr

첫 번째 sed 명령을 stderr에서만 필터로 사용하고 두 번째 sed 명령을 사용하여 결합 된 출력을 수정합니다.

명령을 올바르게 구문 분석하려면 2> 뒤의 공백이 필수입니다.


5

Advanced Bash Scripting Guide 의이 페이지 의 마지막 부분 은 "stderr 만 파이프로 리디렉션"입니다.

# stderr 만 파이프로 리디렉션합니다.

exec 3>&1                              # Save current "value" of stdout.
ls -l 2>&1 >&3 3>&- | grep bad 3>&-    # Close fd 3 for 'grep' (but not 'ls').
#              ^^^^   ^^^^
exec 3>&-                              # Now close it for the remainder of the script.

# 감사합니다, SC

이것은 당신이 원하는 것일 수 있습니다. 그렇지 않다면 ABSG의 다른 부분이 당신을 도울 수있을 것입니다. 그것은 훌륭합니다.


우리는 차이점을 명확하게 표시하지 않고 문서, 처방 및 의견을 혼합하기 때문에 ABSG를 참조로 권장하는 것을 다소 주저합니다. 링크하는 항목이 괜찮아 보이지만 일부 섹션에는 모호한 내용이 있습니다.
tripleee

3

명명 된 파이프를 살펴보십시오.

$ mkfifo err
$ cmd1 2>err |cat - err |cmd2

하지 cat - err표준 출력과 표준 에러의 산재 휴식?
Martin DeMello

@Martin-상황에 따라 다릅니다. cmd1, cat 또는 cmd2가 출력을 버퍼링하면 출력이 순서가 맞지 않는 것을 볼 수 있습니다.
mob
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.