Bash 循环直到某个命令停止失败

Posted

技术标签:

【中文标题】Bash 循环直到某个命令停止失败【英文标题】:Bash loop until a certain command stops failing 【发布时间】:2016-05-26 12:24:25 【问题描述】:

我想在 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 循环重写此示例?

【问题讨论】:

离题了。这里是the same question on Unix.SE。 【参考方案1】:

除了众所周知的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

【讨论】:

当你知道有一个until 循环时非常明显! RTFM 给我。我认为最好的答案。【参考方案2】:

如果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

也许,为什么不呢?

while ! my_command ;do
    echo Loop on my_command
  done

但是从那里你可以更好地使用until as chepner suggest

【讨论】:

好答案!我从来不知道while command1; command2 ; do ... 有效 到目前为止对我来说似乎是赢家。我喜欢!【参考方案3】:

您可以从PIPESTATUS 内置变量中获取否定命令的状态:

while ! my_command ; do
    some_code_dependent_on_exit_code "$PIPESTATUS[0]"
done

chepner 的解决方案在这种情况下更好,但 PIPESTATUS 有时对类似问题很有用。

【讨论】:

好点。我不知道PIPESTATUS 也适用于这种情况。【参考方案4】:

所以在我的情况下,我还需要忽略一些退出代码并希望为用户提供一些有用的输出,所以我写了这个:

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

【讨论】:

以上是关于Bash 循环直到某个命令停止失败的主要内容,如果未能解决你的问题,请参考以下文章

sh Bash:直到,做,做,让,回声:直到循环

循环 bash 脚本,直到 cURL 响应不等于字符串

[Linux Shell学习系列七]Bash循环——1for循环

While 循环在 Bash 的第一行之后停止读取

appium-循环执行一条用例,失败时停止执行

停止代码执行,直到 XMLHttpRequest 循环完成