获取管道命令的退出代码可以正常工作。
echo "ABC" | false | true
echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]}
#Output is 0 1 0
但是当我将输出分配给变量时,a无法获得退出代码。
TEST=$(echo "ABC" | false | true)
echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]}
#Output is 0
如何获取管道进程的退出代码?
答案 0 :(得分:1)
Bash command substitution发生在子shell中,因此这些值只存在于该子shell中。您看到${PIPESTATUS[0]}
反映了作业中的$?
(如果您使用1
结束替换,则会| false
。)
我已将您的示例更改为实际包含一些输出。这也适用于原始代码。
# without command substitution
echo "ABC" | false | echo "DEF"
echo "${PIPESTATUS[*]}"
echo "---"
# within command substitution
TEST="$( echo "ABC" | false | echo "DEF"; printf :%s "${PIPESTATUS[*]}" )"
declare -a PIPESTATUS2=( ${TEST##*:} ) # make array w/ content after final colon
if [[ -n "${TEST%:*}" ]]; then # if there was original output
TEST="${TEST%:*}" # remove trailing results from $TEST
TEST="${TEST%$'\n'}" # remove trailing \n like plain $(…)
else
TEST="" # no original output -> empty string
fi
echo "$TEST"
echo "${PIPESTATUS2[*]}"
输出:
DEF
141 1 0
---
DEF
141 1 0
Exit code 141来自false
过早终止管道(SIGPIPE)的事实。
这基本上只是将子shell的$PIPESTATUS
数组附加到存储的值,使用冒号作为分隔符(任何非数字都可以;我选择了一个我没有必须逃脱),然后将它拉出来在响应之外,使用这些值填充$PIPESTATUS2
数组。删除最后的换行符是另一种基础。我们可以使用它作为分隔符,但如果原始输出没有被换行符终止,那么这会破坏。
更简单的解决方案如果您只是想要one of the exit codes:
TEST=$( echo "ABC" | false | true; exit ${PIPESTATUS[0]} )
echo $? # 141 from `echo "ABC"
更复杂的POSIX兼容解决方案(当你可以使用一些黑魔法时,不需要$PIPESTATUS
):在着名的{§1d中搜索“考虑管道” {3}}咆哮,然后根据您的POSIX兼容需求进行调整。如果您是那种需要避免使用bash和真实语言的编码器,这将是非常重要但具有高度教育性。