오디오 클립의 메타 정보를 얻기 위해 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이 오류 스트림을 읽도록하려면 어떻게해야합니까?
nixCraft 링크를 사용하여 표준 오류 스트림을 표준 출력 스트림으로 리디렉션 한 다음 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으로 리디렉션하지 않으려면 어떻게해야합니까?
bash
를 사용하는 경우 익명 파이프를 사용하지 않는 이유는 무엇입니까?
ffmpeg -i 01-Daemon.mp3 2> >(grep -i Duration)
일반적인 쉘 중 어느 것도 (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
이는 phunehehe의 "temp file trick"과 유사하지만 대신 명명 된 파이프를 사용하여 결과를 출력 할 때 약간 더 가까운 결과를 얻을 수 있으므로 장기 실행 명령에 유용 할 수 있습니다.
$ mkfifo mypipe
$ command 2> mypipe | grep "pattern" mypipe
이 구성에서 stderr은 "mypipe"라는 파이프로 연결됩니다. grep
이 파일 인수와 함께 호출되었으므로 입력을 위해 STDIN을 찾지 않습니다. 불행히도, 일단 당신이 한 후에는 그 명명 된 파이프를 정리해야합니다.
Bash 4를 사용하는 경우 command1 2>&1 | command2
, command1 |& command2
. 그러나 이것은 순전히 구문 바로 가기라고 생각하며 STDERR을 STDOUT으로 리디렉션합니다.
Gilles와 Stefan Lasiewski의 답변은 모두 좋지만이 방법은 더 간단합니다.
ffmpeg -i 01-Daemon.mp3 2>&1 >/dev/null | grep "pattern"
ffmpeg's
stdout을 인쇄하고 싶지 않다고 가정합니다.
작동 방식 :
이 테스트에 사용 된 스크립트는 아래를 참조하십시오.
Grep은 stdin에서만 작동 할 수 있으므로 Grep가 구문 분석 할 수있는 형식으로 stderr 스트림을 변환해야합니다.
일반적으로 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
(위의 명령은 different 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
스트림을 교환 할 수 있습니다. 이렇게하면 원래 표준 오류 스트림을 grep
하면서 터미널에서 원래 표준 출력으로가는 출력을 계속 얻을 수 있습니다.
somecommand 3>&2 2>&1 1>&3- | grep 'pattern'
이것은 먼저 출력을 위해 열린 새 파일 디스크립터 (3)를 작성하고 표준 오류 스트림 (3>&2
). 그런 다음 표준 오류를 표준 출력 (2>&1
). 마지막으로 표준 출력이 원래 표준 오류로 리디렉션되고 새 파일 설명자가 닫힙니다 (1>&3-
).
귀하의 경우 :
ffmpeg -i 01-Daemon.mp3 3>&2 2>&1 1>&3- | grep -i Duration
그것을 테스트 :
$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep "error"
output
error
$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep -v "error"
output
한 명령의 출력을 다른 명령으로 파이프 할 때 (|
), 표준 출력 만 리디렉션하고 있습니다. 그 이유를 설명해야합니다
ffmpeg -i 01-Daemon.mp3 | grep -i Duration
원하는 것을 출력하지 않습니다 (그러나 작동합니다).
오류 출력을 표준 출력으로 리디렉션하지 않으려면 오류 출력을 파일로 리디렉션 한 다음 나중에 grep 할 수 있습니다
ffmpeg -i 01-Daemon.mp3 2> /tmp/ffmpeg-error
grep -i Duration /tmp/ffmpeg-error
bash
는 일반 파이프를 통해 stdout을 stdin 스트림으로 리디렉션 할 수 있습니다-|
또한 stdout과 stderr을 모두 |&
이 경우 rc
Shell을 사용하고 싶습니다.
먼저 패키지를 설치하십시오 (1MB 미만).
다음은 stdout
에서 stderr
를 파이프하고 rc
을 grep하는 방법의 예입니다.
find /proc/ >[1] /dev/null |[2] grep task
Bash를 떠나지 않고도 할 수 있습니다.
rc -c 'find /proc/ >[1] /dev/null |[2] grep task'
아시다시피, 구문은 간단하므로이 방법을 선호합니다.
파이프 문자 바로 뒤에 괄호 안에 파이프 할 파일 설명자를 지정할 수 있습니다.
표준 파일 디스크립터는 다음과 같이 번호가 매겨집니다 :
Bash 서브 프로세스 예제의 변형 :
두 줄을 stderr에 에코하고 st stderr를 파일에 에코하고 티를 grep하고 stdout에 다시 파이프
(>&2 echo -e 'asdf\nfff\n') 2> >(tee some.load.errors | grep 'fff' >&1)
표준 출력 :
fff
some.load.errors (예 : stderr) :
asdf
fff