Bash中单行while循环的语法

857

我在使用分号和/或大括号的组合时遇到了麻烦。我想在命令行上将其作为一行代码完成:

while [ 1 ]
do
    foo
    sleep 2
done

5
将换行符替换为分号。对于for循环也是一样的。 - Tom
24
@Tom:那并不总是有效。在“do”之后,必须有第一个命令,而不是一个分号。 - Stefano Borini
15个回答

1606
while true; do foo; sleep 2; done

顺便提一句,如果你在命令提示符中将它作为多行输入(就像你正在展示的那样),然后使用上箭头调用历史记录,你将得到一个正确标点的单行输出。

$ while true
> do
>    echo "hello"
>    sleep 2
> done
hello
hello
hello
^C
$ <arrow up> while true; do    echo "hello";    sleep 2; done

6
对我而言,“如果您在命令提示符下将其输入为多行(如您所示),然后使用向上箭头调用历史记录,您将获得它的一个单行版本,正确地标点。”这并不成立。 - Vincent Scheib
@VincentScheib,如果你正在使用bash,请检查cmdhist选项? - Alok Singhal
太好了!在Mavericks(Mac OS-X 10.9)上完美运行,并允许我保持VPN连接。Openconnect会因为错误的cookie而在几个小时后断开连接。所以我将openconnect命令放入一个shell脚本中,使用sudo su成为root用户,并使用以下命令:while true; do sh /Users/myuser/bin/vpn ; done - Blisterpeanuts
在bash中对我有用。只需复制粘贴脚本(4行),按Enter键。按Ctrl+C退出。然后按向上箭头。 - undefined

223

也可以在while的条件中使用sleep命令,我认为这样可以使一行代码看起来更加简洁。

while sleep 2; do echo thinking; done

30
这不仅改变了语法 - 它将在休眠后执行命令。在之前的回答中,命令立即执行。这只是需要注意的一点。 - DanGordon
4
当然,如果[while]命令失败,循环将退出,因此您需要使用while echo thinking || true ; do sleep 2 ; done,但这样你会回到while true ; ...。@DanGordon - Brian Carcich

93

冒号始终为“true”:

while :; do foo; sleep 2; done

28
为什么冒号始终为真? - Jürgen Paul
14
从bash man页面(在" SHELL BUILTIN COMMANDS "部分):: [参数] 没有效果;该命令除了展开参数和执行任何指定的重定向外,不做其他任何事情。返回零退出代码。 - Adrian W
6
推荐使用这个语法:因为 ":" 是 shell 内置命令的一部分,也就是说 ":" 是 shell 自带的命令。 - avner
3
@avner:由谁推荐?truedashbash 中都是内置命令。而且,尽管 POSIX 仅要求 true 可执行,但他们写道:“尽管 shell 的特殊内置命令 : 提供了类似的功能,因为 true 在历史脚本中被广泛使用,并且对于新手脚本阅读者来说 不那么晦涩。”(IEEE Std 1003.1-2001)。请参考此问题 - jan-glx

46

你可以使用分号来分隔语句:

$ while [ 1 ]; do foo; sleep 2; done

7
我喜欢这个答案,因为它解释了何时和为什么需要分号。 - superhedgy

37

你也可以使用 until 命令:

until ((0)); do foo; sleep 2; done
请确认以下是否为需要翻译的内容:
Note that in contrast to while, until would execute the commands inside the loop as long as the test condition has an exit status which is not zero.
Using a while loop:
while read i; do foo; sleep 2; done < /dev/urandom

使用 for 循环:

for ((;;)); do foo; sleep 2; done
另一种方法是使用until
until [ ]; do foo; sleep 2; done

“until ((0)); do foo; sleep 2; done”似乎无法正常工作,它会持续无限循环。 - 030

31

使用while循环:

while true; do echo 'while'; sleep 2s; done

使用 for 循环:

for ((;;)); do echo 'forloop'; sleep 2; done

使用递归(与上面略有不同,键盘中断不能停止它)

list(){ echo 'recursion'; sleep 2; list; } && list;

3
使用 sleep 中的单位时要小心,比如 sleep 1h。在我的 zsh 中,它会忽略单位 h 并每秒运行一次命令。先快速查看一下您的环境中 sleep 命令支持哪些选项,可以避免不必要的麻烦。建议先执行 man sleep 命令来查看相关文档。 - Joshua Pinter

17

一个非常简单的无限循环.. :)

while true ; do continue ; done

针对您的问题,答案如下:

while true; do foo ; sleep 2 ; done

12

如果只是想简单地监视进程,请使用watch


9

我喜欢仅在 WHILE 语句中使用分号,而使用 && 运算符可以使循环做更多的事情...

所以我总是这样做。

while true ; do echo Launching Spaceship into orbit && sleep 5s && /usr/bin/launch-mechanism && echo Launching in T-5 && sleep 1s && echo T-4 && sleep 1s && echo T-3 && sleep 1s && echo T-2 && sleep 1s && echo T-1 && sleep 1s && echo liftoff ; done

1
嗯,在循环中使用 && 与任何其他时间的使用方式都是相同的。如果您需要第二件事情只在第一件事情发生时发生,那么请使用 &&,否则 ; 就足够了。实际上,您希望保持该循环的内容简短而简单,最好只有一个命令,因此可以使用函数或脚本。 - thecoshman
使用 sleep 中的单位时要小心,比如 sleep 1h。在我的 zsh 中,它会忽略单位 h 并每秒运行一次命令。先快速查看一下你的环境中 sleep 命令支持哪些选项,可以避免不必要的麻烦。建议先执行 man sleep 命令来查看相关文档。 - Joshua Pinter
谢谢您。我正在寻找在“do”中运行多个任务的正确方法。 - jjaguirre394

7
如果你希望在某个条件下停止 while 循环,并且当该条件满足时,你的 foo 命令返回非零值,则可以使用以下方法中断循环:
while foo; do echo 'sleeping...'; sleep 5; done;

例如,假设foo命令是批量删除元素的,当没有可删除的元素时返回1。
如果您有一个需要运行某个命令直到满足某个条件的自定义脚本,那么这将非常有效。在满足条件时,您编写脚本退出并使用1,当应再次运行时则使用0
例如,假设您有一个Python脚本batch_update.py,它会更新数据库中的100行,并且如果有更多行需要更新,则返回0;如果没有更多行需要更新,则返回1。使用以下命令,可以每次更新100行,并在更新之间休眠5秒钟:
while batch_update.py; do echo 'sleeping...'; sleep 5; done;

和如何退出? - AK_
当您想要退出while循环时,可以通过让foo命令以代码1的状态退出来实现。我已经在我的答案中更新了一个示例。 - Yep_It's_Me

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接