首页 > 系统服务 > 详细

Linux中对管道命令中的任意子命令进行返回码校验

时间:2020-03-04 09:06:40      阅读:68      评论:0      收藏:0      [点我收藏+]

~~ linux return code with pipeline~~
~~ linux 管道命令中的返回码~~

BASH?SHELL中,通常使用?$??来获取上一条命令的返回码。

Shell Scripting Tutorial - Checking the exit status of ANY command in a pipeline

对于管道中的命令,使用$?只能获取管道中最后一条命令的返回码,例如:

${RUN_COMMAND} 2> "${CUR_DIR}"/weiflow-from-weiclient.log | ${WEIBOX_UTIL_HOME}/rotatelogs.py -n 3 "${CUR_DIR}"/weiflow-from-weiclient.log 500M

使用?$PIPESTATUS来获取管道中每个命令的返回码。

注意:

  1. PIPESTATUS?是一个数组,第一条命令的返回码存储在${PIPESTATUS[0]},以此类推。

  2. 如果前一条命令不是一个管道,而是一个单独的命令,命令的返回码存储为${PIPESTATUS[0]},此时${PIPESTATUS[0]}同$?值相同(事实上,PIPESTATUS最后一个元素的值总是与$?的值相同)

  3. 每执行一条命令,切记PIPESTATUS都会更新其值为上一条命令的返回码,

??????cat?/not/a/valid/filename|cat
??????if?[?${PIPESTATUS[0]}?-ne?0?];?then?echo?${PIPESTATUS[@]};?fi

??????上例中执行完管道后,${PIPESTATUS[0]}值为1,${PIPESTATUS[1]}值为0

??????但是上面的脚本执行完成后,输出为0,这是因为if?分支的测试命令值为真,然后?PIPESTATUS[0]的值此时被置为0。应当在命令执行完成后立即在同一个测试命令中对所有值进行测试,例如?

??????if?[?${PIPESTATUS[0]}?-eq?1?-a?${PIPESTATUS[1]}?-eq?0?]?;?then?echo?something;?fi

或者先将$PIPESTATUS数组保存下来,以后再处理,例如

??????ret=${PIPESTATUS[@]};

RESULT

${RUN_COMMAND} 2> "${CUR_DIR}"/weiflow-from-weiclient.log | ${WEIBOX_UTIL_HOME}/rotatelogs.py -n 3 "${CUR_DIR}"/weiflow-from-weiclient.log 500M
exit \${PIPESTATUS[0]}

Checking the exit status of ANY command in a pipeline

  • It‘s a pretty common thing in a shell script to want to check the exit status of the previous command. You can do this with the $? variable, as is widely known:
#!/bin/bash
grep some.machine.example.com /etc/hosts
if [ "$?" -ne "0" ]; then
  # The grep command failed to find "some.machine.example.com" in /etc/hosts file
  echo "I don't know the IP address of some.machine.example.com"
  exit 2
fi
  • What gets difficult is when you execute a pipeline: (see pipelines for more information on the Unix Pipeline)
#!/bin/bash
grep some.machine.example.com /etc/hosts 2>&1 | tee /tmp/hosts-results.txt
if [ "$?" -ne "0" ]; then
  # Ah - what we get here is the status of the "tee" command, 
  # not the status of the "grep" command :-(
  • What you get is the result of the tee command, which writes the results to the display as well as to the /tmp/hosts-results.txt file.

  • To find out what grep returned, $? is of no use.

  • Instead, use the ${PIPESTATUS[]} array variable. ${PIPESTATUS[0]} tells us what grep returned, while ${PIPESTATUS[1]} tells us what tee returned.

  • So, to see what grep found, we can write our script like this:

#!/bin/bash
grep some.machine.example.com /etc/hosts 2>&1 | tee /tmp/hosts-results.txt
if [ "${PIPESTATUS[0]}" -ne "0" ]; then
  # The grep command failed to find "some.machine.example.com" in /etc/hosts file
  echo "I don't know the IP address of some.machine.example.com"
  exit 2
fi

Here‘s The Rub

  • The downside is, that any command you use to access ${PIPESTATUS[]}, will automatically replace the current state of the array with the return code of the command you have just run:
Pipeline (command) PIPESTATUS shows status of:
grep ... tee ...
echo "Grep returned ${PIPESTATUS[0]}" echo "Grep ...
echo "Maybe PIPESTATUS isn‘t so useful after all" echo "Maybe ...
  • So as soon as we use echo to tell us about the return code of grep, the ${PIPESTATUS[]} array now tells us about the return code of the echo statement itself, which is pretty likely to be zero, as not much can cause echo to fail!

The Fix

  • Because ${PIPESTATUS[]} is a special variable, it changes all the time. However, we can copy this array into another array, which is just a regular array, which will not be changed at all just by running some more commands. Copying an array requires a slightly different syntax to simply copying contents of a variable into another:

  • RC=( "${PIPESTATUS[@]}" )
  • Where RC stands for Return Code. We can then investigate the status of RC at our leisure. For testing purposes, the program true always returns zero, and false always returns 1:
#!/bin/bash
echo "tftf"
true | false | true | false
RC=( "${PIPESTATUS[@]}" )
echo "RC[0] = ${RC[0]}"     # true = 0
echo "RC[1] = ${RC[1]}"     # false = 1
echo "RC[2] = ${RC[2]}"     # true = 0
echo "RC[3] = ${RC[3]}"     # false = 1

echo "ftft"
false | true | false | true
RC=( "${PIPESTATUS[@]}" )
echo "RC[0] = ${RC[0]}"     # false = 1
echo "RC[1] = ${RC[1]}"     # true = 0
echo "RC[2] = ${RC[2]}"     # false = 1
echo "RC[3] = ${RC[3]}"     # true = 0

echo "fftt"
false | false | true | true
RC=( "${PIPESTATUS[@]}" )
echo "RC[0] = ${RC[0]}"     # false = 1
echo "RC[1] = ${RC[1]}"     # false = 1
echo "RC[2] = ${RC[2]}"     # true = 0
echo "RC[3] = ${RC[3]}"     # true = 0

Linux中对管道命令中的任意子命令进行返回码校验

原文:https://www.cnblogs.com/suanec/p/12405775.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!