Bash 中单行 while 循环的语法

Syntax for a single-line while loop in Bash

提问人:Brian Deacon 提问时间:8/18/2009 最后编辑:oguz ismailBrian Deacon 更新时间:5/1/2023 访问量:994509

问:

我无法想出分号和/或大括号的正确组合。我想这样做,但作为命令行中的单行:

while [ 1 ]
do
    foo
    sleep 2
done
bash 循环 while-loop

评论

5赞 Tom 8/18/2009
将换行符替换为分号。这同样适用于 for 循环。
24赞 Stefano Borini 8/18/2009
@Tom:这并不总是有效。在 do 之后,您必须具有第一个命令,而不是分号

答:

1606赞 Stefano Borini 8/18/2009 #1
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 1/10/2013
“如果您在命令提示符下将其键入为多行(如您所示),然后用箭头向上调用历史记录,您将在一行上获得正确标点符号。” 对我来说不是真的。
0赞 Alok Singhal 3/6/2013
@VincentScheib,检查选项是否使用bash?cmdhist
0赞 Blisterpeanuts 3/4/2015
非常好!在 Mavericks (Mac OS-X 10.9) 上完美运行,并允许我保持 vpn 运行。Openconnect 在几个小时后断开连接,并出现错误的 cookie 错误。所以我把 openconnect 命令放在一个 shell 脚本中,sudo su 成为 root,并使用这个 cmd 行:while true; do sh /Users/myuser/bin/vpn ; done
0赞 Indika K 11/9/2023
在 bash 中为我工作。只需复制粘贴脚本(4 行),按回车键即可。按 Ctrl+C 退出。然后按向上箭头。
46赞 mipadi 8/18/2009 #2

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

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

评论

7赞 superhedgy 5/19/2017
我喜欢这个答案,因为它解释了何时以及为什么;(分号)为必填项。
9赞 Thomas 1/29/2011 #3

我喜欢只对 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 7/7/2015
好吧,循环中的使用与其他任何时间都一样,真的不是吗。您是否需要仅当第一件事发生时才发生第二件事,然后使用其他就足够了。实际上,您希望该循环的内容简短明了,理想情况下只有一个命令,例如函数或脚本。&&&&;
0赞 Joshua Pinter 6/26/2020
小心使用 中的单位,例如 。在我的 zsh 中,它忽略该单元并每 1 秒运行一次我的命令。首先快速查看环境的命令支持哪些内容。可能会让您省去头痛。sleepsleep 1hhman sleepsleep
0赞 jjaguirre394 2/10/2021
谢谢你。我一直在寻找在“做”中运行不止一件事的正确方法
2赞 Roger 7/3/2011 #4

如果我能举两个实际的例子(带有一点“情感”)。

这将写入文件夹“img”中所有以“.jpg”结尾的文件的名称:

for f in *; do if [ "${f#*.}" == 'jpg' ]; then echo $f; fi; done

这将删除它们:

for f in *; do if [ "${f#*.}" == 'jpg' ]; then rm -r $f; fi; done

只是想做出贡献。

评论

1赞 Kevin Fegan 1/20/2014
@JKnight - 对于这些示例,您不会只执行 ls -1 *.jpg 和 rm *.jpg
2赞 Marian 4/24/2015
两者都不是无限循环,也不是 while 循环。
223赞 Anssi 11/2/2012 #5

也可以在 while 的条件下使用睡眠命令。恕我直言,让单行看起来更干净。

while sleep 2; do echo thinking; done

评论

30赞 DanGordon 10/27/2016
好吧,这不仅仅是更改语法 - 它将在睡眠后执行命令。在前面的答案中,命令立即执行。只是需要注意的事情。
4赞 Brian Carcich 11/15/2019
@DanGordon 当然,如果 [while] 命令失败,循环就会退出,所以你必须这样做,但随后你又回到了while echo thinking ; do sleep 2 ; donewhile echo thinking || true ; do sleep 2 ; donewhile true ; ...
93赞 ajaaskel 11/6/2012 #6

冒号总是“真的”:

while :; do foo; sleep 2; done

评论

28赞 Jürgen Paul 12/12/2013
为什么冒号总是真的?
14赞 Adrian W 1/18/2014
@Pineapple Under the Sea:从 bash 手册页:(在 SHELL BUILTIN COMMANDS 部分中)无效;该命令除了扩展参数和执行任何指定的重定向外,不执行任何操作。返回零退出代码。: [arguments]
6赞 avner 2/26/2014
建议将此语法作为 : 是 shell 本身的一部分,即 : 是 shell 内置命令。
3赞 jan-glx 7/16/2023
@avner:由谁推荐? 是内置的,也是。虽然 posix 只需要作为可执行文件,但他们写道:“即使 shell 特殊内置:提供类似的功能,因为 * ( IEEE Std 1003.1-2001)。另请参阅此问题truedashbashtruetrue``* is widely used in historical scripts and *is less cryptic to novice script readers*.
37赞 devnull 8/25/2013 #7

您还可以使用命令:until

until ((0)); do foo; sleep 2; done

请注意,与 相反,只要测试条件的退出状态不为零,就会在循环中执行命令。whileuntil


使用循环:while

while read i; do foo; sleep 2; done < /dev/urandom

使用循环:for

for ((;;)); do foo; sleep 2; done

另一种使用方式:until

until [ ]; do foo; sleep 2; done

评论

0赞 030 4/18/2019
似乎不起作用。它连续无限。until ((0)); do foo; sleep 2; done
17赞 Mack 7/9/2015 #8

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

while true ; do continue ; done

你的问题是:

while true; do foo ; sleep 2 ; done
12赞 Christian Schwarz 12/14/2016 #9

对于简单的过程监视,请改用watch

2赞 grepit 2/8/2017 #10

你也可以试试这个 警告:你不应该这样做,但由于问题是要求无限循环,没有尽头......这就是你如何做到的。

while [[ 0 -ne 1 ]]; do echo "it's looping";   sleep 2; done

评论

0赞 gniourf_gniourf 2/8/2017
你为什么要这样做?
3赞 grepit 2/8/2017
因为发布问题的布莱恩·迪肯(Brian Deacon)想要一个无限循环。给猫剥皮的方法不止一种,仅此而已
0赞 TheTechRobo the Nerd 2/25/2021
你为什么不应该?
7赞 Yep_It's_Me 5/16/2017 #11

如果您希望 while 循环在某个条件后停止,并且您的命令在满足此条件时返回非零,那么您可以像这样让循环中断:foo

while foo; do echo 'sleeping...'; sleep 5; done;

例如,如果命令正在批量删除内容,并且在没有要删除的内容时返回 1。foo

如果您有一个自定义脚本,该脚本需要多次运行命令,直到出现某种情况,则这很有效。编写脚本以在满足条件时退出,并在应再次运行时退出。10

例如,假设您有一个 python 脚本,该脚本更新数据库中的 100 行,如果有更多要更新的行,如果没有更多行,则返回。以下命令将允许您一次更新第 100 行,并在更新之间休眠 5 秒:batch_update.py01

while batch_update.py; do echo 'sleeping...'; sleep 5; done;

评论

0赞 AK_ 1/18/2018
你会如何退出?
0赞 Yep_It's_Me 1/18/2018
当您希望 while 循环中断时,可以使用代码使命令退出。我用一个例子更新了我的答案。foo1
31赞 Muhammad Soliman 5/26/2019 #12

用:while

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

使用循环:for

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

使用 ,(与上面略有不同,键盘中断不会停止它)Recursion

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

评论

3赞 Joshua Pinter 6/26/2020
小心使用 中的单位,例如 。在我的 zsh 中,它忽略该单元并每 1 秒运行一次我的命令。首先快速查看环境的命令支持哪些内容。可能会让您省去头痛。sleepsleep 1hhman sleepsleep
6赞 Victor Yarema 11/25/2020 #13

您甚至不需要使用 和 .对于无限循环,我发现使用大括号更具可读性。例如:dodonefor

for ((;;)) { date ; sleep 1 ; }

这在 和 中有效。在 中不起作用。bashzshsh

1赞 michal-michalak 6/16/2021 #14

您也可以将该循环置于后台(例如,当您需要断开与远程计算机的连接时)

nohup bash -c "while true; do aws s3 sync xml s3://bucket-name/xml --profile=s3-profile-name; sleep 3600; done &"

评论

0赞 Sridhar Sarnobat 9/12/2022
我一直试图避免这种情况,因为(坏?)原因,即您的编辑器可能不会将字符串上下文突出显示为程序 sytnax。
0赞 RARE Kpop Manifesto 5/1/2023 #15

在(甚至更早)中,您还可以通过运行循环条件中的所有内容来反转 的作用,但改用循环正文:bash 5::

while ( gdate +"%c ( %s.%-N )" && sleep 0.71  ) do :; done  # discards side-effects
      
while { gdate +"%c ( %s.%-N )" && sleep 0.71; } do :; done  # no sub-shell needed

+ gdate '+%c ( %s.%-N )'
Sun Apr 30 12:38:25 2023 ( 1682872705.498728 )
+ sleep 0.71
+ :

+ gdate '+%c ( %s.%-N )'
Sun Apr 30 12:38:26 2023 ( 1682872706.218152 )
+ sleep 0.71

... 

同时更宽容,即使没有zsh:

while; do gdate +'%c ( %s.%-N )' && sleep 0.31 ; done

Sun Apr 30 12:46:09 2023 ( 1682873169.469092 )
Sun Apr 30 12:46:09 2023 ( 1682873169.789560 )
Sun Apr 30 12:46:10 2023 ( 1682873170.105635 )
Sun Apr 30 12:46:10 2023 ( 1682873170.424766 )