Bash 如何使用stdout和stderr io重定向从程序中获取正常的错误/警告消息输出?

Bash 如何使用stdout和stderr io重定向从程序中获取正常的错误/警告消息输出?,bash,zsh,io-redirection,Bash,Zsh,Io Redirection,我有一个程序,输出到stdout和stderr,但没有以正确的方式使用它们。一些错误进入标准输出,一些进入标准输出,无错误的东西进入标准输出,它打印出标准输出的很多信息。要解决此问题,我想创建一个管道来执行以下操作: 将$cmd(从stderr和stdout)的所有输出保存到文件$logfile(不要将其打印到屏幕) 过滤掉stderr和stdout上的所有警告和错误消息(从警告|错误到空行),并只对“错误”字着色(将输出重定向到stderr) 将步骤2的输出保存到文件$logfile:r.st

我有一个程序,输出到stdout和stderr,但没有以正确的方式使用它们。一些错误进入标准输出,一些进入标准输出,无错误的东西进入标准输出,它打印出标准输出的很多信息。要解决此问题,我想创建一个管道来执行以下操作:

  • $cmd
    (从stderr和stdout)的所有输出保存到文件
    $logfile
    (不要将其打印到屏幕)
  • 过滤掉stderr和stdout上的所有警告和错误消息(从警告|错误到空行),并只对“错误”字着色(将输出重定向到stderr)
  • 将步骤2的输出保存到文件
    $logfile:r.stderr
  • 从命令中使用正确的退出代码退出
  • 到目前为止,我有:

    $!/bin/zsh
    # using zsh 4.2.0
    setopt no_multios
    
    # Don't error out if sed or grep don't find a match:
    alias -g grep_err_warn="(sed -n '/error\|warning/I,/^$/p' || true)"
    alias -g color_err="(grep --color -i -C 1000 error 1>&2 || true)"
    alias -g filter='tee $logfile | grep_err_warn | tee $logfile:r.stderr | color_err'
    
    # use {} around command to avoid possible race conditions:
    { eval $cmd } 2>&1 | filter
    exit $pipestatus[1]
    
    我试过很多方法,但都不能成功。我读过“从Bash到zshell”,很多帖子,等等。我目前的问题是:

  • 只有stdin进入过滤器

  • 注意:
    $cmd
    是一个shell脚本,它使用
    /usr/bin/time-p
    前缀调用二进制文件。这似乎会导致管道出现问题,这就是为什么我要将命令包装在
    {…}
    中,所有输出都进入管道。

    我没有可用的zsh

    我确实注意到您的
    {..}
    'd语句不正确

    在结束“}”之前总是需要分号

    当我在bash中添加这一点时,我可以满意地证明stderr被重定向到stdout

    试一试

    还有,你写了

    保存$cmd的所有输出(表单stderr) 和stdout)转换为文件$logfile

    我没有看到你的代码中提到$logfile。 您应该能够使用

    我希望这有帮助


    另外,当您看起来是新用户时,如果您得到一个有助于您的答案,请记住将其标记为已接受,并/或给它一个+(或-)作为有用的答案。

    不要在脚本中使用别名,请使用函数(全局别名特别麻烦)。并不是说你真的需要函数。您也不需要
    |true
    (除非您在
    set-e
    下运行,在这种情况下,您应该在此处将其关闭)。除此之外,你的脚本看起来还不错;什么东西噎住了

    { eval $cmd } |
    tee $logfile |
    sed -n '/error\|warning/I,/^$/p' |
    tee $logfile:r.stderr |
    grep --color -i -C 1000 error 1>&2
    exit $pipestatus[1]
    

    我也不知道你所说的sed表达是什么意思;我不太理解你的要求2。

    最初的帖子基本上是正确的,除了Gilles的优化(关闭
    set-e
    ,因此不需要
    |true

    #!/bin/zsh
    # using zsh 4.2.0
    setopt no_multios
    #setopt no_errexit # set -e # don't turn this on
    
    { eval $cmd } 2>&1 |
    tee $logfile |
    sed -n '/error\|warning/I,/^$/p' |
    tee $logfile:r.stderr |
    grep --color -i -C 1000 error 1>&2
    exit $pipestatus[1]
    

    让我困惑的是,stdout和stderr的混合导致了它们的交错,并且
    sed-n'/error\| warning/I,/^$/p'
    (从打印出来,错误| |警告到下一个空行)打印出来的内容比预期的要多得多,这使得命令似乎不起作用。

    {eval$cmd
    在zsh下工作。
    $logfile
    出现在
    过滤器
    别名中。嗨,Gilles,sed行打印出所有包含“error”或“warning”的行以及后面的所有行,直到出现一个空行。这完成了需求2的前半部分。另一半带有“grep--color…1>&2”Gilles,感谢关于
    |t的提示rue
    。我有
    setopt errexit
    set(与
    set-e
    相同)。
    { eval $cmd } |
    tee $logfile |
    sed -n '/error\|warning/I,/^$/p' |
    tee $logfile:r.stderr |
    grep --color -i -C 1000 error 1>&2
    exit $pipestatus[1]
    
    #!/bin/zsh
    # using zsh 4.2.0
    setopt no_multios
    #setopt no_errexit # set -e # don't turn this on
    
    { eval $cmd } 2>&1 |
    tee $logfile |
    sed -n '/error\|warning/I,/^$/p' |
    tee $logfile:r.stderr |
    grep --color -i -C 1000 error 1>&2
    exit $pipestatus[1]