Bash:检查多管道命令链的退出状态

时间:2013-12-13 10:49:19

标签: bash pipe snmp exit-code command-substitution

我在检查多管命令链中的某个命令是否引发错误时遇到问题。通常这不难检查,但set -o pipefail和检查${PIPESTATUS[@]}都不适用于我的情况。设置如下:

cmd="$snmpcmd $snmpargs $agent $oid | grep <grepoptions> for_stuff | cut -d',' f$fields | sed 's/ubstitute/some_other_stuff/g'"

注1:该命令经过彻底测试,运行良好。

现在,我想将该命令的输出存储在名为procdata的数组中。因此,我做了:

declare -a procdata
procdata=( $(eval $cmd) )

注意2:eval是必要的,否则$snmpcmd会引发invalid option -- <grepoption>错误,这是没有意义的,因为<grepoption>不是$snmpcmd选项明显。在这个阶段,我认为这是$snmpcmd的错误,但这是另一个节目......

如果发生错误,procdata将为空。但是,由于两个不同的原因,它可能是空的:要么因为执行$snmpcmd时发生错误(例如超时),要么因为grep无法找到它要查找的内容。问题是,我需要能够区分这两种情况并单独处理它们。

因此,set -o pipefail不是一个选项,因为它会传播任何错误,我无法区分管道的哪个部分失败。另一方面echo ${PIPESTATUS[@]}0之后总是procdata=( $(eval $cmd) ),即使我有很多管道!?然而,如果我在提示符下直接执行整个命令并立即调用echo ${PIPESTATUS[@]},它会正确返回所有管道的退出状态。

我知道我可以将错误的流绑定到stdout但是我必须使用启发式方法来检查procdata中的元素是有效还是错误消息,并且我冒着获得误报的风险。我还可以将stdout传递给/dev/null并仅捕获错误流并检查是否${#procdata[@]} -eq 0。但我必须重复调用以获取实际数据,整个命令的时间成本很高(大约3-5s)。我不想两次打电话。或者我可以使用临时文件来写错误,但我宁愿这样做而没有创建/删除文件的开销。

任何想法如何让我在bash中工作?

由于

P.S:

$ echo $BASH_VERSION
4.2.37(1)-release

1 个答案:

答案 0 :(得分:3)

这里有很多事情:

(1)当您说eval $cmd并尝试获取命令$cmd中包含的管道中的进程的退出值时,echo "${PIPESTATUS[@]}"将仅包含 eval的退出状态。而不是eval,您需要提供完整的命令行。

(2)您需要在将管道输出分配给变量时获取PIPESTATUS。试图在以后这样做是行不通的。


举个例子,你可以说:

foo=$(command | grep something | command2; echo "${PIPESTATUS[@]})"

这会将管道输出和PIPESTATUS数组捕获到变量foo中。

您可以通过说:

将命令输出到数组中
result=($(head -n -1 <<< "$foo"))

PIPESTATUS数组说

tail -1 <<< "$foo"