Bash - 获取返回代码,stdout和stderr形成管道调用

时间:2015-09-02 07:44:50

标签: bash pipe stdout stderr

我制作了一个简单的记录器,它有方法logMETHOD。它的工作是

  1. stderrstdout放入变量log(以及稍后的全球_LOG变量)
  2. stderrstderr stdout上打印已调用方法的stdout,以便我可以在控制台中看到它。
  3. 返回被调用函数的返回码。
  4. 它的调用如下所示:

    logMETHOD myMethod arg1 arg2 arg3
    

    我想出了如何将标准和错误输出放到log变量和控制台,但我无法获得正确的返回码。

    到目前为止我的代码:

    function logMETHOD {
        exec 5>&1
        local log
        log="$($1 ${@:2} 2>&1 | tee /dev/fd/5)"
        local retVal=$?
        _LOG+=$log$'\n'
        return $retVal
    }
    

    不幸的是,我得到的返回码来自(可能)分配一个值(或者来自tee)。

    奖金问题: 如果没有2>&1stdoutstderr连接到控制台,是否有可能实现我的目标?

    我用' PIPESTATUS'测试了解决方案。但代码仍为0。

    function main {
        logMETHOD alwaysError
    }
    
    function logMETHOD {
        exec 5>&1
        local log
        local retVal
        log="$( "$@" 2>&1 | tee /dev/fd/5 )"
        retVal=${PIPESTATUS[0]}
        echo "RETVAL: $retVal"
        echo "LOG: $log"
        _LOG+=$log$'\n'
        return $retVal
    }
    
    function alwaysError {
        return 1
    }
    
    main $@
    

2 个答案:

答案 0 :(得分:1)

PIPESTATUS将是一个很好的解决方案,但在这里它已经保留了log=...赋值的返回值。如果你想要"$@"...的返回值,你必须这样写:

log="$( "$@" 2>&1 | tee /dev/fd/5; echo ${PIPESTATUS[0]}>/tmp/retval )"
retVal=$(</tmp/retval)

将它分配给变量是行不通的,因为它的作用域不会扩展到调用shell,因此你必须使用临时文件。

至于stderr$()只能提取stdout,因此如果你想单独处理它,你也必须使用临时文件。

log="$( "$@" 2>/tmp/stderr | tee /dev/fd/5; echo ${PIPESTATUS[0]}>/tmp/retval )"
stderr_log=$(</tmp/stderr)
retVal=$(</tmp/retval)

如果你只是想省去重定向:

log="$( "$@" |& tee /dev/fd/5; echo ${PIPESTATUS[0]}>/tmp/retval )"

来自man bash

  

如果|&amp;使用命令的标准错误,除标准输出外,还通过管道连接到command2的标准输入;它是2&gt;&amp; 1 |的简写。标准错误到标准输出的隐式重定向是在命令指定的任何重定向之后执行的。

答案 1 :(得分:0)

最简单的解决方法是使用PIPESTATUS来检索命令的退出状态。

# There's no need to split $1 off of $@ to run the command.
log=$( "$@" 2>&1 | tee /dev/fd/5 )
local retVal=${PIPESTATUS[0]}