直到/同时和链 $?

直到/同时和链 $?

我想循环执行命令,直到它以退出代码退出0,所以我尝试了:

$ while/until $?; do $command; done

until/while似乎只接受布尔值 liketrue/false和 not 0/1

我是否错过了类似的东西[[ ]]或其他东西?

答案1

while关键字until需要一个命令作为他们的论点。如果命令返回零退出状态,表示“成功”,while将运行循环体中的命令,until不是运行循环体中的命令。

您的代码似乎使用whileand untilwith $?(最近命令的退出状态)作为命令。除非系统上有以整数作为名称的命令,否则这将不起作用。什么工作是使用test命令将其与 进行比较0,例如,与

until test "$?" -eq 0; do some-command; done

或者,使用缩写形式test

until [ "$?" -eq 0 ]; do some-command; done

现在的问题显然是$?进入循环时很可能为零,从而阻止循环运行一次。让命令本身直接将其退出状态提供给whileor会更有意义until(除非您想通过在循环之前$?调用eg 来初始化为非零值,这看起来很奇怪)。false

使用标准 POSIX(虽然不是 Bourne,但现在这并不重要)shell 语法:

while ! some-command; do continue; done

或(Bourne 和 POSIX),

until some-command; do continue; done

这两个命令都会运行,some-command直到返回零退出状态(“成功”)。在每次迭代中,它都会执行continue循环体内的关键字。执行continue会立即跳到循环的下一次迭代,但您可以将其替换为 egsleep 5以便在每次迭代中都有短暂的延迟,或者使用:which 不执行任何操作。

另一种变体是有一个无穷命令成功时退出的循环:

while true; do some-command && break; done

或者,稍微冗长一点,并添加空气以提高可读性,

while true; do
    if some-command; then
        break
    fi
done

唯一一次你真正需要使用$?是当您需要跟踪该值一段时间时,如

somefunction () {
    grep -q 'pattern' file
    ret=$?
    
    if [ "$ret" -ne 0 ]; then
        printf 'grep failed with exit code %s\n' "$ret"
    fi >&2
    
    return "$ret"
}

在上面的代码中,退出状态$?由测试重置[ "$ret" -ne 0 ],如果不将其存储在单独的变量中,我们将无法打印它的值,也无法从函数返回它。


另一件需要指出的事情是,你似乎在使用细绳$command(未引用),作为您的命令。这将是好多了如果要运行存储在变量中的命令,请使用数组:

thecommand=( awk -F ',' 'BEGIN { "uptime" | getline; split($4,a,": "); if (a[2] > 5) exit 1 }' )

while ! "${thecommand[@]}"; do sleep 5; done

(此示例代码每隔 5 秒休眠一次,直到 1 分钟平均系统负载低于 5。)

请注意,通过使用数组并引用扩展 as "${thecommand[@]}",我可以运行命令,而不必担心 shell 如何将字符串拆分为单词并对每个单词应用文件名通配符。

也可以看看我们如何运行存储在变量中的命令?有关您的问题这方面的更多信息。

答案2

你可以这样做:

false; while [[ $? -ne 0 ]]; do
  command
done

在这里,false最初将设置$?为非零值,允许循环至少运行一次。然后循环运行给定的命令,直到它以零退出状态退出。

相关内容