我正在使用ffmpeg获取音频剪辑的元信息。但是我无法grep它。

    $ 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无法读取错误流以捕获匹配的行。

使用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怎么办?

评论

我相信grep只能在stdout上运行(尽管我找不到规范的源来支持它),这意味着任何流都需要首先转换为stdout。

@Stefan:grep只能在stdin上运行。它是由外壳程序创建的管道,它将grep的stdin连接到另一个命令的stdout。而且外壳程序只能将标准输出连接到标准输入。

糟糕,您是对的。我想这就是我真正想说的,只是我没有彻底考虑。谢谢@Giles。

您是否仍要打印标准输出?

这是ZSH方式:unix.stackexchange.com/questions/265061/…

#1 楼

如果您使用的是bash,为什么不使用匿名管道,实质上是phunehehe表示的缩写:

ffmpeg -i 01-Daemon.mp3 2> >(grep -i Duration)

评论


+1好!仅重击,但比其他方法更干净。

– Mikel
2011年2月8日,下午1:43

+1我用它来检查cp输出cp -r dir *到2>>(grep -v“ svn”)

–贝塔利斯塔
2014年8月15日14:08

如果您要再次在stderr上过滤过滤的重定向输出,请添加>&2,例如命令2>>(grep something>&2)

– tlo
16年5月6日在9:16

请解释这是如何工作的。 2>将stderr重定向到文件,我明白了。这将从文件>(grep -i持续时间)中读取。但是文件从不存储吗?这种技术叫什么,以便我能进一步了解它?

– MarkoAvlijaš
18年5月23日在10:57

@MarkoAvlijaš查找进程替换。 “进程替换还可以用于捕获通常会进入文件的输出,并将其重定向到进程的输入。”

– Wisbucky
19年1月4日,0:57

#2 楼

除了从stdout到stdin之外,所有普通的shell(甚至zsh)都不允许管道。但是,所有的Bourne风格的shell都支持文件描述符重新分配(如1>&2所示)。因此,您可以暂时将stdout转移到fd 3,然后将stderr转移到stdout,然后再将fd 3放回stdout。保持标准输出不变,可以使用stuff

$ 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


评论


这种方法有效。不幸的是,在我的情况下,如果返回一个非零的返回值,它会丢失-返回的值对我来说是0。这可能并不总是发生,但在我目前正在研究的情况下会发生。有什么办法可以保存吗?

– Faheem Mitha
16年4月26日在22:08

@FaheemMitha不确定您在做什么,但也许pipestatus会有所帮助

–吉尔斯'所以-不再是邪恶的'
16年4月26日在23:15

@FaheemMitha,也设置为-o pipefail可能会有所帮助,这取决于您要对错误状态进行的处理。 (例如,如果您已将-e设置为打开,则在发生任何错误时失败,那么您可能还希望设置-o pipefail。)

–通配符
16年4月26日在23:21

@Wildcard是的,我已将-e设置为打开,以防出现任何错误。

– Faheem Mitha
16年4月26日在23:33

rc外壳允许配管stderr。请参阅下面的答案。

–罗夫
19年9月4日在18:55

#3 楼

这类似于phunehehe的“临时文件技巧”,但改用命名管道,使您可以在输出结果时使其更接近输出,这对于长时间运行的命令可能非常方便:

$ mkfifo mypipe
$ command 2> mypipe | grep "pattern" mypipe


在此构造中,stderr将定向到名为“ mypipe”的管道。由于已经使用文件参数调用了grep,因此它将不会使用STDIN作为输入。不幸的是,完成后,您仍然必须清理该命名管道。

如果您使用的是Bash 4,则command1 2>&1 | command2的快捷语法为command1 |& command2。但是,我认为这纯粹是语法快捷方式,您仍在将STDERR重定向到STDOUT。

评论


相关:stackoverflow.com/questions/2871233/…

– Stefan Lasiewski
2010-10-26 18:00

该|&语法非常适合清除肿的Ruby stderr堆栈跟踪。我终于可以让那些没有太多麻烦的人了。

– pgr
18年4月2日在11:28

#4 楼

Gilles和Stefan Lasiewski的答案都不错,但是这种方法比较简单:

ffmpeg -i 01-Daemon.mp3 2>&1 >/dev/null | grep "pattern"


我假设您不希望打印ffmpeg's stdout。

工作方式:


先管道


ffmpeg和grep启动,ffmpeg的stdout转到grep的stdin


重定向,从左到右


ffmpeg的stderr设置为其标准输出(当前为管道)
ffmpeg的stdout设置为/ dev / null




评论


这种描述使我感到困惑。最后两个项目符号使我想到“将stderr重定向到stdout”,然后“将stdout(现在带有stderr)重定向到/ dev / null”。但是,这并不是真正的作用。这些说法似乎是相反的。

–史蒂夫
15年9月24日在15:15

@Steve第二个项目符号中没有“ with stderr”。您是否看到过unix.stackexchange.com/questions/37660/order-of-redirections?

– Mikel
2015年9月24日15:30在

不,我的意思是我对您用英语的描述方式的解释。但是,您提供的链接非常有用。

–史蒂夫
15年9月24日在17:50

为什么需要将其重定向到/ dev / null?

– Kanwaljeet Singh
19-09-30在8:59

因此,stdout消失了,只剩下stderr,否则grep将对ffmpeg生成的stdout和stderr的混合流进行操作

– aularon
19年11月21日在6:25

#5 楼

有关这些测试中使用的脚本,请参见下文。

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上运行。您仍然可以grep文本。

$ ./stdout-stderr.sh 2>&1 >/dev/null | grep err
./stdout-stderr.sh: Printing to stderr


(请注意,上述命令不同于./command >/dev/null 2>&1,这是一个非常常见的命令)。

这是用于测试的脚本。这会将一行输出到stdout,并将一行输出到stderr:

#!/bin/sh

# Print a message to stdout
echo "q4312078q: Printing to stdout"
# Print a message to stderr
echo "q4312078q: Printing to stderr" >&2

exit 0


评论


如果切换重定向,则不需要所有花括号。只需执行./stdout-stderr.sh 2>&1> / dev / null | grep err。

– Mikel
2011年2月8日在1:45

#6 楼

当将一个命令的输出通过管道传递给另一个命令时(使用|),您仅在重定向标准输出。因此,这应该可以解释为什么

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功能感兴趣,这将使我重定向stderr。 (但不是临时文件的技巧)

–安德鲁·杜夫涅(Andrew-Dufresne)
10-10-26在4:07

@Andrew我的意思是,该命令按照其设计工作方式运行。它只是不能按您想要的方式工作:)

– phunehehe
2010-10-26 4:25

我不知道有什么方法可以将命令的错误输出重定向到另一个命令的标准输入。如果有人可以指出这一点将会很有趣。

– phunehehe
10-10-26在4:31

#7 楼

您可以交换流。这将使您能够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


#8 楼

我想在这种情况下使用rc外壳。

首先安装该软件包(小于1MB)。

这是如何丢弃stdout和管道的示例将stderr转换为rc中的grep:

find /proc/ >[1] /dev/null |[2] grep task

无需离开Bash就可以做到:

rc -c 'find /proc/ >[1] /dev/null |[2] grep task'

可能已经注意到,语法很简单,这使它成为我的首选解决方案。

您可以在管道字符之后指定要在括号中管道传输的文件描述符。

标准文件描述符的编号方式如下:


0:标准输入
1:标准输出
2:标准错误


#9 楼

bash可以通过常规管道将stdout重定向到stdin流-|
也可以通过|&将stdout和stderr都重定向到stdin

#10 楼

bash子流程示例的一种变体:

将两行回传到stderr和tee stderr到文件,grep tee并通过管道返回到stdout

(>&2 echo -e 'asdf\nfff\n') 2> >(tee some.load.errors | grep 'fff' >&1)


stdout:

fff


一些加载错误(例如stderr):

asdf
fff


#11 楼

尝试使用此命令


使用随机名称创建文件
将输出发送到文件
将文件的内容发送到管道
grep

ceva->只是一个变量名(英语=某物)

ceva=$RANDOM$RANDOM$RANDOM; ffmpeg -i qwerty_112_0_0_record.flv 2>$ceva; cat $ceva | grep Duration; rm $ceva;


评论


我会使用/ tmp / $ ceva,而不是用临时文件乱丢当前目录-并且您假设当前目录是可写的。

–罗夫
19-09-4在18:48