I used to write my scripts like this:

some_command
while [ $? -ne 0 ] ; do
    sleep 1
    some_command
done

It always irked me that I have to write some_command twice. Can I put it inside the loop test section somehow?

up vote 20 down vote accepted

You could use some_command as your test condition.

while ! some_command; do sleep 1; done

The condition will remain true as long as some_command exits with an error.

Or a more verbose way if you want to do additional checks:

while ! some_command
do 
    # add more if desired
    sleep 1
done
  • This looks better than mine, even though it is a one-liner ;-) – Anthon Dec 22 '14 at 15:46
  • The OP might want to split it into several lines should he need to execute several commands upon failure, though :) – John WH Smith Dec 22 '14 at 15:50
  • No reason why you can't line-break it at the semi-colons to make it multi-line. – Mark Stewart Dec 22 '14 at 16:03
  • 1
    ... or write while ! some_command; do several; commands; sleep 1; done – ignis Dec 23 '14 at 18:04

This is what the until loop is for:

until some_command
do    sleep 1
done

It is the logical negation of a while loop.

The spec says:

The until Loop

  • The until loop shall continuously execute one compound-list as long as another compound-list has a non-zero exit status.

  • The format of the until loop is as follows:

    until compound-list-1
    do    compound-list-2
    done
  • The compound-list-1 shall be executed, and if it has a zero exit status, the until command completes. Otherwise, the compound-list-2 shall be executed, and the process repeats.

You can just do:

false
while [ $? -ne 0 ] ; do
   sleep 1
   some_command
done

this has the disadvantage though that it always sleeps one second first

If you want to be able to exit on any of a number of commands to exit with 0 you can do :

while true; do
  if [ some_command ] ; then break ; fi
  if [ some_other_command ] ; then break ; fi
  sleep 1
done

which of course also works for just some_command

  • 5
    The second example shouldn't include [ and ] around the commands. – nyuszika7h Dec 22 '14 at 23:14

Neither while ! ... nor until ... works on the systems that froze their shell environment prior to POSIX.1-2001. This, however, does.

while :; do
    if some command; then
        break
    fi
    sleep 1
done

If you don't need total portability, why are you writing a shell script? Perl is more likely to be available than Bash.

sleep 1 while 0 != system qw(some command);

(As above, the sleep is only executed if the command fails.)

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.