直到/同时和链 $?

aab*_*aab 2 shell scripting bash shell-script

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

$ while/until $?; do $command; done
Run Code Online (Sandbox Code Playgroud)

until/while似乎只接受布尔值true/false而不是0/1.

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

Kus*_*nda 15

whileuntil关键字需要一个命令作为他们的论点。如果命令返回零退出状态,信号“成功”,while将在循环体运行的命令,同时until不会在循环体运行的命令。

您的代码似乎使用whileuntil$?,最近命令的退出状态,作为一个命令。这将不起作用,除非您在系统上有以整数作为名称的命令。什么的工作就是使用test命令把它比对0,例如,与

until test "$?" -eq 0; do some-command; done
Run Code Online (Sandbox Code Playgroud)

或者,使用 的缩写形式test

until [ "$?" -eq 0 ]; do some-command; done
Run Code Online (Sandbox Code Playgroud)

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

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

until [ "$?" -eq 0 ]; do some-command; done
Run Code Online (Sandbox Code Playgroud)

或(伯恩和 POSIX),

while ! some-command; do continue; done
Run Code Online (Sandbox Code Playgroud)

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

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

until some-command; do continue; done
Run Code Online (Sandbox Code Playgroud)

或者,稍微详细一点,并增加了可读性,

while true; do some-command && break; done
Run Code Online (Sandbox Code Playgroud)

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

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

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


另一件要指出的事情是,您似乎在使用字符串, $command(未加引号)作为您的命令。这将是更好的,如果你想运行存储在一个变量的命令使用数组:

while true; do
    if some-command; then
        break
    fi
done
Run Code Online (Sandbox Code Playgroud)

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

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

另请参阅我们如何运行存储在变量中的命令?有关您问题的这方面的更多信息。