5

我在检查多管道命令链中的某个命令是否引发错误时遇到问题。通常这并不难检查,但在我的情况下也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[@]}立即调用,它会正确返回所有管道的退出状态。

我知道我可以将 err 流绑定到标准输出,但我必须使用启发式方法来检查其中的元素procdata是有效消息还是错误消息,并且我冒着误报的风险。我还可以通过管道将 stdout 传输到/dev/null并仅捕获错误流并检查${#procdata[@]} -eq 0. 但是我必须重复调用才能获取实际数据,并且整个命令的时间成本很高(大约 3-5 秒)。我不想叫它两次。或者我可以使用一个临时文件来写入错误,但我宁愿这样做,而不需要创建/删除文件的开销。

有什么想法可以让我在 bash 中完成这项工作吗?

谢谢

PS:

$ echo $BASH_VERSION
4.2.37(1)-release
4

1 回答 1

3

这里有很多事情:

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

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


例如,您可以说:

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

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

您可以通过以下方式将命令输出放入数组中:

result=($(head -n -1 <<< "$foo"))

PIPESTATUS数组说

tail -1 <<< "$foo"
于 2013-12-13T11:44:38.757 回答