Bash - 获取 return 代码、stdout 和 stderr 形式的管道调用
Bash - getting return code, stdout and stderr form piped invocations
我做了一个简单的记录器,它有方法logMETHOD
。它的工作是
- 将
stderr
和 stdout
放入变量 log
(然后放入我的全局 _LOG
变量)
- 在
stderr
上打印 stderr
并在 stdout
上打印 stdout
以便我可以在控制台中看到它。
- Return 被调用函数的 return 代码。
它的调用看起来像这样:
logMETHOD myMethod arg1 arg2 arg3
我想出了如何将标准和错误输出同时输出到 log
变量和控制台,但我无法获得正确的 return 代码。
到目前为止我的代码:
function logMETHOD {
exec 5>&1
local log
log="$( ${@:2} 2>&1 | tee /dev/fd/5)"
local retVal=$?
_LOG+=$log$'\n'
return $retVal
}
不幸的是,我得到的 return 代码来自(可能)赋值(或者可能来自 tee
)。
奖金问题:
如果没有 2>&1
连接 stdout
和 stderr
也用于控制台,是否有可能实现我的目标?
我用 '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 $@
最简单的修复方法是使用 PIPESTATUS
检索命令的退出状态。
# There's no need to split off of $@ to run the command.
log=$( "$@" 2>&1 | tee /dev/fd/5 )
local retVal=${PIPESTATUS[0]}
PIPESTATUS
将是一个很好的解决方案,但这里它已经包含 log=...
赋值的 return 值。如果你想要 "$@"...
的 return 值,你必须这样写:
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
:
If |& is used, command's standard error, in addition to its standard output, is connected to command2's standard input through the pipe; it is shorthand for 2>&1 |. This implicit redirection of the standard error to the standard output is performed after any redirections specified by the command.
我做了一个简单的记录器,它有方法logMETHOD
。它的工作是
- 将
stderr
和stdout
放入变量log
(然后放入我的全局_LOG
变量) - 在
stderr
上打印stderr
并在stdout
上打印stdout
以便我可以在控制台中看到它。 - Return 被调用函数的 return 代码。
它的调用看起来像这样:
logMETHOD myMethod arg1 arg2 arg3
我想出了如何将标准和错误输出同时输出到 log
变量和控制台,但我无法获得正确的 return 代码。
到目前为止我的代码:
function logMETHOD {
exec 5>&1
local log
log="$( ${@:2} 2>&1 | tee /dev/fd/5)"
local retVal=$?
_LOG+=$log$'\n'
return $retVal
}
不幸的是,我得到的 return 代码来自(可能)赋值(或者可能来自 tee
)。
奖金问题:
如果没有 2>&1
连接 stdout
和 stderr
也用于控制台,是否有可能实现我的目标?
我用 '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 $@
最简单的修复方法是使用 PIPESTATUS
检索命令的退出状态。
# There's no need to split off of $@ to run the command.
log=$( "$@" 2>&1 | tee /dev/fd/5 )
local retVal=${PIPESTATUS[0]}
PIPESTATUS
将是一个很好的解决方案,但这里它已经包含 log=...
赋值的 return 值。如果你想要 "$@"...
的 return 值,你必须这样写:
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
:
If |& is used, command's standard error, in addition to its standard output, is connected to command2's standard input through the pipe; it is shorthand for 2>&1 |. This implicit redirection of the standard error to the standard output is performed after any redirections specified by the command.