programing

필터를 통과하는 파이프만 STDERR

showcode 2023. 5. 20. 11:03
반응형

필터를 통과하는 파이프만 STDERR

Bash에서 STDERR을 STDOUT와 통합하기 전에 필터를 통해 파이프로 연결할 수 있는 방법이 있습니까?즉, 나는 원합니다.

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

보다는

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

다음은 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. 첫 번째 stdout을 &3으로 저장(&1은 3으로 속음)
  2. 다음 stdout을 stderr로 전송(&2는 1로 속음)
  3. &3(stdout)으로 stderr 전송(&3은 2로 속음)
  4. close &3 (&-는 3으로 속음)

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의 STDOUT는 원래 STDERR로 돌아갑니다.

프로세스 대체를 순진하게 사용하면 다음을 필터링할 수 있는 것 같습니다.stderr와는 별도로stdout:

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

참고:stderr에 나오다stderr그리고.stdoutstdout전체를 다른 하위 셸로 포장하고 파일로 리디렉션하면 볼 수 있습니다.o그리고.e

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

TL;DR: (배시 및 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

그래서, 이것의 가정과 어설픈 구문을 고려할 때, 당신은 더 단순한 것을 사용하는 것이 더 나을 것입니다.bash/zsh구문은 위의 TL;DR에 표시되며 여기에 설명되어 있습니다.


실제 시연, 그랩핑 전용 stderr:

$ ls -l . noexistABC noexistXYZ
ls: cannot access 'noexistABC': No such file or directory
ls: cannot access 'noexistXYZ': No such file or directory
.:
total 4
-rw-rw-r-- 1 frank frank    0 Aug 19 12:26 bar.txt
-rw-rw-r-- 1 frank frank    0 Aug 19 12:26 foo.txt
drwxrwxr-x 2 frank frank 4096 Aug 19 12:26 someFolder


$ ( ls -l . noexistABC noexistXYZ 2>&1 >&3 3>&- | grep ABC >&2 3>&-) 3>&1
.:
ls: cannot access 'noexistABC': No such file or directory
total 4
-rw-rw-r-- 1 frank frank    0 Aug 19 12:26 bar.txt
-rw-rw-r-- 1 frank frank    0 Aug 19 12:26 foo.txt
drwxrwxr-x 2 frank frank 4096 Aug 19 12:26 someFolder

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> 뒤에 공백이 있어야 합니다.

고급 Bash 스크립팅 가이드의 이 페이지 마지막 부분은 "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.

감사합니다, S.C.

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

명명된 파이프를 살펴봅니다.

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

언급URL : https://stackoverflow.com/questions/3618078/pipe-only-stderr-through-a-filter

반응형