我想在bash中编写一个循环,执行直到某个命令停止失败(返回非零退出代码),如下所示:
while ! my_command; do
# do something
done
但是在这个循环中我需要检查返回的退出代码my_command
,所以我尝试了这个:
while ! my_command; do
if [ $? -eq 5 ]; then
echo "Error was 5"
else
echo "Error was not 5"
fi
# potentially, other code follows...
done
然后特殊变量?
在循环体内变为0
。
显而易见的解决方案是:
while true; do
my_command
EC=$?
if [ $EC -eq 0 ]; then
break
fi
some_code_dependent_on_exit_code $EC
done
如何检查循环体内my_command
的退出代码(在循环标题中调用),而不使用带有中断条件的while true
循环重写此示例,如上所示?
答案 0 :(得分:15)
除了众所周知的while
循环之外,POSIX还提供until
循环,无需否定my_command
的退出状态。
# To demonstrate
my_command () { read number; return $number; }
until my_command; do
if [ $? -eq 5 ]; then
echo "Error was 5"
else
echo "Error was not 5"
fi
# potentially, other code follows...
done
答案 1 :(得分:4)
如果true
命令伤害了你的敏感度,你可以写:
while my_command ; ret=$? ; [ $ret -ne 0 ];do
echo do something with $ret
done
这可以简化:
while my_command ; ((ret=$?)) ;do
echo do something with $ret
done
但如果您不需要 ResultCode ,您可以简单地:
while my_command ; [ $? -ne 0 ];do
echo Loop on my_command
done
或
while my_command ; (($?)) ;do
echo Loop on my_command
done
但是从那里你可以更好地使用until
as chepner suggest
答案 2 :(得分:2)
您可以从PIPESTATUS
内置变量中获取否定命令的状态:
while ! my_command ; do
some_code_dependent_on_exit_code $PIPESTATUS
done
在这种情况下,chepner的解决方案更好,但PIPESTATUS
有时对类似的问题很有用。
答案 3 :(得分:0)
因此,在我的情况下,我还需要忽略一些退出代码,并希望向用户提供一些有用的输出,因此我将其写成:
retrycmd(){
MSG=$1
IGNORE=$2
shift 2
local SLEEP_T=5
local L_CNT=5
local C_CNT=0
while ((C_CNT++ < ${L_CNT})) && ! $@;do
RET=${PIPESTATUS[0]}
#echo "RET: ${RET}"
for I in ${IGNORE//,/ };do # bashism: replace(/) all(/) match(,) with(/) value(<space>)
if ((${RET} == ${I}));then
#echo "${RET} = ${I}"
break 2
fi
done
echo "${MSG} failure ${C_CNT}"
sleep ${SLEEP_T}
done
if ((${C_CNT} > ${L_CNT}));then
echo "${MSG} failed"
poweroff
fi
}
#retrycmd "Doing task" "IGNORE,CSV" <CMD>
retrycmd "Ping google" "0" ping www.google.com