【问题标题】:Bash: Pipe stdout and catch stderr into a variableBash:管道标准输出并将标准错误捕获到一个变量中
【发布时间】:2016-02-24 11:25:13
【问题描述】:

是否可以将普通的stdout 进一步传送到另一个程序,但将stderr 存储到变量中?

这是用例:

mysqldump database | gzip > database.sql

在这种情况下,我想捕获mysqldump 产生的所有错误/警告并将它们存储到一个变量中,但正常的stdout(即转储)应继续通过管道传输到gzip

关于如何实现这一点的任何想法?

【问题讨论】:

  • 您可以尝试将流 1 和 2 重定向到不同的目的地,并将 stderr 文件读入 var

标签: bash stdout stderr


【解决方案1】:

您可以执行以下操作:

mysqldump database 2> dump_errors | gzip > database.sql
error_var=$( cat dump_errors )
rm dump_errors

在这里,mysqldump 的所有错误都被重定向到一个名为“dump_errors”的文件,标准输出通过管道传送到gzip,而gzip 又写入database.sql

然后将“dump_errors”的内容分配给变量“error_val”,然后删除文件“dump_errors”。


注意以下重定向:

$ sort 1> output 2> errors   # redirects stdout to "output", stderr to "errors"
$ sort 1> output 2>&1        # stderr goes to stdout, stdout writes to "output"
$ sort 2> errors 1>&2        # stdout goes to stderr, stderr writes to "errors"

$ sort 2>&1 > output         # tie stderr to screen, redirect stdout to "output"
$ sort > output 2>&1         # redirect stdout to "output", tie stderr to "output"

【讨论】:

  • 这是否可能不需要额外的文件?
  • 查看 muru 的解决方案。一般来说,如果你想使用管道,那么你不能在管道中创建变量,因为管道在一个子shell中运行,一旦你退出变量就不会持续存在,因此需要额外的文件。但如果你不使用管道,那么你可以取消额外的文件。
  • 感谢您提供更多信息。但是,我将接受 muru 的回答,因为它可以在没有 tmpfies 的情况下完成所有工作。
【解决方案2】:

你可以这样做:

errors=$(mysqldump database 2>&1 > >(gzip > database.sql))

在这里,我使用进程替换来获取gzip 以使用mysqldump 的输出作为标准输入。鉴于the order of redirections (2>&1 before >)mysqldump 的标准错误现在应该用于命令替换。

测试一下:

$ a=$(sh -c 'echo foo >&2; echo bar' 2>&1 > >(gzip > foo))
$ gunzip < foo
bar
$ echo $a
foo

【讨论】:

  • 是否也可以同时存储退出代码和两个错误消息(mysqldumpgzip),以便之后我可以单独检查它们?
  • @lockdoc 恐怕不用这种方式。您可以使用$? 获取mysqldump 的退出代码,但gzip 状态丢失。
猜你喜欢
  • 1970-01-01
  • 2018-08-10
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多