我遇到了一个问题,需要检查多管道命令链中是否有某个命令抛出了错误。通常这并不难检查,但在我的情况下,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[@]}
在执行procdata=( $(eval $cmd) )
之后总是返回0
!?。但是,如果我直接在提示符处执行整个命令,然后立即调用echo ${PIPESTATUS[@]}
,它会正确地返回所有管道的退出状态。我知道我可以将错误流绑定到标准输出,但我必须使用启发式方法来检查
procdata
中的元素是有效还是错误消息,并且我冒着得到错误结果的风险。我也可以将标准输出导向/dev/null
并仅捕获错误流,然后检查${#procdata[@]} -eq 0
是否成立。但我需要重复调用来获取实际数据,并且整个命令时间成本很高(约3-5秒)。我不想调用两次。或者我可以使用一个临时文件来写入错误信息,但我宁愿不使用创建/删除文件的开销。有什么办法可以使这在bash中工作吗?
谢谢。
$ echo $BASH_VERSION
4.2.37(1)-release
cmdargs
赋值为 "-CHf, -m$mibs -v$snmpver -c$community $agent";本地变量procdatacmd
赋值为 "$tblcmd $cmdargs $proc_table ";接着,将 "<proc1> -e <proc2>" 的结果通过管道符号(|)传递给procdatacmd
变量进行处理。处理过程中使用了cut
命令和grep
命令,并对结果进行了排序、去重和格式转换,最后用sed
命令进行替换。然后使用${PIPESTATUS[@]}
命令打印出了处理的状态码。接下来使用declare -a procdata=( $(head -n -1 <<< $procdatacmd) )
命令将处理后的数据存储到数组procdata
中,但是输出为空,什么也没有。<proc1> 和 <proc2> 在代理上运行正常。 - user3040975temp=$($tblcmd $cmdargs $proc_table | cut -d',' -f$fields | $( get_pgreplist ) | sort | uniq -c | sed 's/^ *\|\"/ /g;s/ /,/g' ; echo ${PIPESTATUS[@]})
。现在procdata=( $(head -n -1 <<< $temp) )
没有输出任何内容,但是procdata=( $(head <<< $temp) )
逐行输出正确的值?!我很困惑... - user30409751 0 1 0 0 0
表示已经捕获到了退出代码。只需要输入echo "${temp}"
来查看它返回了什么。 - devnullecho "${temp}"
输出10,httpd,runnable 64,nfsd,runnable 0 0 0 0 0 0
。搜索http
输出0 0 1 0 0 0
,表示无法匹配,而虚假的 IP 将给出预期的1 0 1 0 0 0
。再次感谢!可惜我不能投票支持,因为声望不够... - user3040975