%EC%9D%84%20%EC%96%B4%EB%96%BB%EA%B2%8C%20grep%ED%95%A9%EB%8B%88%EA%B9%8C%3F.png)
오디오 클립의 메타 정보를 얻기 위해 ffmpeg를 사용하고 있습니다. 하지만 나는 그것을 잡을 수 없습니다.
$ ffmpeg -i 01-Daemon.mp3 |grep -i Duration
FFmpeg version SVN-r15261, Copyright (c) 2000-2008 Fabrice Bellard, et al.
configuration: --prefix=/usr --bindir=/usr/bin
--datadir=/usr/share/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib
--mandir=/usr/share/man --arch=i386 --extra-cflags=-O2
...
확인해 보니 이 ffmpeg 출력이 stderr로 전달됩니다.
$ ffmpeg -i 01-Daemon.mp3 2> /dev/null
그래서 grep은 일치하는 라인을 잡기 위해 오류 스트림을 읽을 수 없다고 생각합니다. grep에서 오류 스트림을 읽으려면 어떻게 해야 합니까?
사용닉 크래프트링크를 통해 표준 오류 스트림을 표준 출력 스트림으로 리디렉션한 다음 grep이 작동했습니다.
$ ffmpeg -i 01-Daemon.mp3 2>&1 | grep -i Duration
Duration: 01:15:12.33, start: 0.000000, bitrate: 64 kb/s
하지만 stderr을 stdout으로 리디렉션하고 싶지 않다면 어떻게 해야 할까요?
답변1
bash
익명 파이프를 사용하지 않는 이유는 기본적으로 phunehehe가 말한 내용을 축약한 것입니다 .
ffmpeg -i 01-Daemon.mp3 2> >(grep -i Duration)
답변2
|
모든 일반 쉘(zsh도 포함)은 stdout에서 stdin을 제외하고 연산자가 있는 파이프를 허용하지 않습니다. 그러나 모든 Bourne 스타일 쉘은 파일 설명자 재할당(예: 1>&2
)을 지원합니다. 따라서 일시적으로 stdout을 fd 3으로 이동하고, stderr을 stdout으로 이동한 다음 fd 3을 다시 stdout에 넣을 수 있습니다. stuff
stdout에서 일부 출력을 생성하고 stderr에서 일부 출력을 생성하고 표준 출력에 영향을 주지 않고 오류 출력에 적용하려는 경우 filter
이를 사용할 수 있습니다 { stuff 2>&1 1>&3 | filter 1>&2; } 3>&1
.
$ stuff () {
echo standard output
echo more output
echo standard error 1>&2
echo more error 1>&2
}
$ filter () {
grep a
}
$ { stuff 2>&1 1>&3 | filter 1>&2; } 3>&1
standard output
more output
standard error
Ksh, bash 및 zsh는 임의의 파일 설명자에서 파이프를 지원하지만 다르게 작동합니다. 하나의 명령이 기본 명령이고 입력 또는 출력을 다른 명령으로 파이프할 수 있습니다.프로세스 대체기본 명령의 리디렉션에 사용할 수 있는 파이프에 연결된 표준 입력 또는 표준 출력을 사용하여 백그라운드에서 명령을 실행합니다. 여기서는 표준 오류를 필터링하려고 하므로 이를 출력 프로세스 대체로 리디렉션합니다.
$ stuff () {
echo standard output
echo more output
echo standard error 1>&2
echo more error 1>&2
}
$ filter () {
grep a
}
$ stuff 2> >(filter)
standard output
more output
standard error
>
두 문자 사이에 공백이 있다는 점에 유의하십시오 . 이는 2>
표준 출력 및 >(…)
프로세스 대체를 리디렉션하기 위한 것입니다. 2>>…
추가 리디렉션으로 해석되므로 공백이 필요합니다 .
답변3
이는 phunehehe의 "임시 파일 트릭"과 유사하지만 명명된 파이프를 사용하여 출력에 약간 더 가까워질 수 있으며 이는 장기 실행 명령에 매우 편리합니다.
$ mkfifo mypipe
$ command 2> mypipe | grep "pattern" mypipe
이 구성에서 stderr는 "mypipe"라는 파이프로 연결됩니다. 파일 매개변수로 호출 되었으므로 grep
입력을 얻기 위해 STDIN을 찾지 않습니다. 불행하게도 작업을 마친 후에도 명명된 파이프를 정리해야 합니다.
Bash 4를 사용하는 경우 단축 구문이 command1 2>&1 | command2
있습니다 command1 |& command2
. 그러나 나는 이것이 순전히 구문 지름길이라고 생각하며 여전히 STDERR을 STDOUT으로 리디렉션하고 있습니다.
답변4
이 테스트에 사용된 스크립트는 아래를 참조하세요.
Grep은 stdin에서만 작동할 수 있으므로 stderr 스트림을 Grep이 구문 분석할 수 있는 형식으로 변환해야 합니다.
일반적으로 stdout과 stderr이 모두 화면에 인쇄됩니다.
$ ./stdout-stderr.sh
./stdout-stderr.sh: Printing to stdout
./stdout-stderr.sh: Printing to stderr
stdout을 숨기지만 여전히 stderr을 인쇄하려면 다음을 수행하십시오.
$ ./stdout-stderr.sh >/dev/null
./stdout-stderr.sh: Printing to stderr
그러나 grep은 stderr에서 실행되지 않습니다! 다음 명령을 사용하면 "err"이 포함된 줄이 표시되지 않을 것으로 예상할 수 있지만 그렇지 않습니다.
$ ./stdout-stderr.sh >/dev/null |grep --invert-match err
./stdout-stderr.sh: Printing to stderr
해결책은 다음과 같습니다.
다음 Bash 구문은 stdout에 대한 출력을 숨기지만 여전히 stderr을 표시합니다. 먼저 stdout을 /dev/null로 파이프한 다음 stderr를 stdout으로 변환합니다. 왜냐하면 Unix 파이프는 stdout에서만 작동할 수 있기 때문입니다. 여전히 텍스트를 찾을 수 있습니다.
$ ./stdout-stderr.sh 2>&1 >/dev/null | grep err
./stdout-stderr.sh: Printing to stderr
(위 명령은 다음과 같습니다.다른then 은 ./command >/dev/null 2>&1
매우 일반적인 명령입니다).
테스트용 스크립트입니다. 그러면 stdout에 한 줄, stderr에 한 줄이 인쇄됩니다.
#!/bin/sh
# Print a message to stdout
echo "$0: Printing to stdout"
# Print a message to stderr
echo "$0: Printing to stderr" >&2
exit 0