897

I am having trouble coming up with the right combination of semicolons and/or braces. I'd like to do this, but as a one-liner from the command line:

while [ 1 ]
do
    foo
    sleep 2
done
2
  • 5
    replace newlines with semicolons. The same works for for loops.
    – Tom
    Commented Aug 17, 2009 at 16:34
  • 24
    @Tom: that doesn't always work. after the do, you must have the first command, not a semicolon Commented Aug 17, 2009 at 16:38

15 Answers 15

1672
while true; do foo; sleep 2; done

By the way, if you type it as a multiline (as you are showing) at the command prompt and then call the history with arrow up, you will get it on a single line, correctly punctuated.

$ while true
> do
>    echo "hello"
>    sleep 2
> done
hello
hello
hello
^C
$ <arrow up> while true; do    echo "hello";    sleep 2; done
4
  • 6
    "if you type it as a multiline (as you are showing) at the command prompt and then call the history with arrow up, you will get it on a single line, correctly punctuated." was not true for me. Commented Jan 9, 2013 at 21:35
  • @VincentScheib, check cmdhist option if you are using bash? Commented Mar 5, 2013 at 18:56
  • Excellent! Works perfectly on Mavericks (Mac OS-X 10.9) and allows me to keep a vpn running. Openconnect disconnects after a few hours with a bad cookie error. So I put the openconnect command in a shell script, sudo su to become root, and use this cmd line: while true; do sh /Users/myuser/bin/vpn ; done Commented Mar 4, 2015 at 14:19
  • Worked for me in bash. Just copy paste the script (4 lines), press enter. Press Ctrl+C to exit. Then press up arrow.
    – Indika K
    Commented Nov 8, 2023 at 21:55
232

It's also possible to use sleep command in while's condition. Making one-liner looking more clean imho.

while sleep 2; do echo thinking; done
2
  • 34
    Well this does more than just changing the syntax - it will execute the command after the sleep. In the previous answer, the command is executed right away. Just something to note.
    – DanGordon
    Commented Oct 26, 2016 at 16:29
  • 4
    @DanGordon while echo thinking ; do sleep 2 ; done Of course if the [while] command fails, the loop exits, so you would have to while echo thinking || true ; do sleep 2 ; done but then you are back to while true ; ... Commented Nov 14, 2019 at 21:18
100

Colon is always "true":

while :; do foo; sleep 2; done
4
  • 31
    why is colon always true? Commented Dec 12, 2013 at 15:10
  • 17
    @Pineapple Under the Sea: From the bash man page: (in section SHELL BUILTIN COMMANDS) : [arguments] No effect; the command does nothing beyond expanding arguments and performing any specified redirections. A zero exit code is returned.
    – Adrian W
    Commented Jan 17, 2014 at 21:45
  • 6
    this syntax is recommended as : is part of shell itself i.e. : is a shell builtin command.
    – avner
    Commented Feb 25, 2014 at 17:59
  • 3
    @avner: recommended by whom? true is a builtin in dash and bash as well. And while posix requires true only as executable they write: "even though the shell special built-in : provides similar functionality, because *true``* is widely used in historical scripts and *is less cryptic to novice script readers*. ( IEEE Std 1003.1-2001). See also this question
    – jan-glx
    Commented Jul 16, 2023 at 12:56
47

You can use semicolons to separate statements:

$ while [ 1 ]; do foo; sleep 2; done
1
  • 7
    I like this answer because it explains when and why ; (semicolon) is required.
    – superhedgy
    Commented May 19, 2017 at 10:29
40

You can also make use of until command:

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

Using a for loop:

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

Another way using until:

until [ ]; do foo; sleep 2; done
1
  • The until ((0)); do foo; sleep 2; done does not seem to work. It continuous infinite.
    – 030
    Commented Apr 18, 2019 at 12:05
35

Using while:

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

Using for Loop:

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

Using Recursion, (a little bit different than above, keyboard interrupt won't stop it)

list(){ echo 'recursion'; sleep 2; list; } && list;
1
  • 4
    Careful using units in sleep, like sleep 1h. In my zsh, it ignores the unit h and runs my command every 1 second. Do a quick man sleep to see what your environment's sleep command supports first. May save you a headache. Commented Jun 25, 2020 at 16:07
18

A very simple infinite loop.. :)

while true ; do continue ; done

Fr your question it would be:

while true; do foo ; sleep 2 ; done
12

For simple process watching use watch instead

1
  • watch -n 1 "echo hi" Commented Jan 18, 2024 at 5:30
9

I like to use the semicolons only for the WHILE statement, and the && operator to make the loop do more than one thing...

So I always do it like this

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
3
  • 1
    Well, the use of && in the loop is the same as any other time really isn't it. Do you need the second thing to happen only if the first happens, then use && else ; suffices. Really, you want to keep the contents of that loop short and simple, ideally just one command, so a function or a script.
    – thecoshman
    Commented Jul 7, 2015 at 13:03
  • Careful using units in sleep, like sleep 1h. In my zsh, it ignores the unit h and runs my command every 1 second. Do a quick man sleep to see what your environment's sleep command supports first. May save you a headache. Commented Jun 25, 2020 at 16:08
  • Thank you for this. I was looking for the correct way of running more than one thing in the 'do' Commented Feb 9, 2021 at 21:21
8

If you want the while loop to stop after some condition, and your foo command returns non-zero when this condition is met then you can get the loop to break like this:

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

For example, if the foo command is deleting things in batches, and it returns 1 when there is nothing left to delete.

This works well if you have a custom script that needs to run a command many times until some condition. You write the script to exit with 1 when the condition is met and exit with 0 when it should be run again.

For example, say you have a python script batch_update.py which updates 100 rows in a database and returns 0 if there are more to update and 1 if there are no more. The the following command will allow you to update rows 100 at a time with sleeping for 5 seconds between updates:

while batch_update.py; do echo 'sleeping...'; sleep 5; done;
2
  • and how would you exit?
    – AK_
    Commented Jan 17, 2018 at 22:45
  • You make the foo command exit with code 1 when you want the while loop to break. I've updated my answer with an example. Commented Jan 18, 2018 at 2:31
7

You don't even need to use do and done. For infinite loops I find it more readable to use for with curly brackets. For example:

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

This works in bash and zsh. Doesn't work in sh.

3

You can try this too WARNING: this you should not do but since the question is asking for infinite loop with no end...this is how you could do it.

while [[ 0 -ne 1 ]]; do echo "it's looping";   sleep 2; done
3
  • Why would you even do that? Commented Feb 7, 2017 at 21:02
  • 4
    because Brian Deacon which posted the question wanted like an infinte loop. It's more than one way to skin a cat that's all
    – grepit
    Commented Feb 7, 2017 at 21:51
  • Why should you not? Commented Feb 25, 2021 at 1:43
2

If I can give two practical examples (with a bit of "emotion").

This writes the name of all files ended with ".jpg" in the folder "img":

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

This deletes them:

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

Just trying to contribute.

2
  • 1
    @JKnight - for these examples, wouldn't you just do ls -1 *.jpg and rm *.jpg Commented Jan 19, 2014 at 21:31
  • 2
    Both are not infinite loops and not while loops.
    – Marian
    Commented Apr 23, 2015 at 21:38
2

You can also put that loop in the background (e.g. when you need to disconnect from a remote machine)

nohup bash -c "while true; do aws s3 sync xml s3://bucket-name/xml --profile=s3-profile-name; sleep 3600; done &"
2
  • I've always tried to avoid this for the (bad?) reason that your editor may not highlight the string context as program sytnax. Commented Sep 12, 2022 at 0:02
  • I use this structure: nohup bash -c "while true; do COMMAND; sleep 3600; done" > MY.LOG &
    – parvus
    Commented Oct 21, 2024 at 6:05
0

in bash 5 (or perhaps even earlier), you can also reverse the role of the : by running everything in the loop criteria but using : in the loop body instead :

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

... 

meanwhile zsh is even more forgiving, and willing to loop even without the :

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 )

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.