home about me

Repeat a shell command until it succeeds

Sometimes you just need to try again. And again, and again…

The Problem

From time to time there will be instances where you need to have a shell command run repeatedly until it succeeds. While most of the time this is indicative of underlying issues, sometimes a fix that is just good enough will be good enough.

Two cases I recently encountered:

  • For a tiny legacy project I rarely have to make changes on, the build process would just sometimes fail. Of course, the ‘right’ solution is to fix whatever causes the failures, but time is a finite resource and in this case it really wasn’t worth the effort.
  • I needed to push code to a fresh repository, but did not yet have write permissions to it. The admin was unavailable, but I had to leave, so naturally the thing to do was to have the machine git pushup‘ing until permissions were granted and the command succeeds.

The Solution

In the easiest form, the solution would look like this:

until git pushup
do
  sleep 10
done

Simply replace git pushup with the command you want to succeed and sleep 10 with the commands you want run inbetween attempts. I decided to go with sleep 10 to have a pause of 10 seconds between each request and not run afoul of rate limits. You could simply echo something to not have a delay.

If you need a shorter notation, for example to be used in an npm command, semicolons can be used:

until git pushup; do sleep 10; done

This is also useful if you have a certain condition you’re waiting for. You could, for example, keep pinging the network address of your roommate’s phone to get notified once he comes home and is in wifi range:

until ping -c 1 -t 5 192.168.178.1
do
  sleep 1
done
echo '\007'

The parameters for the ping command are important to get this working right. -c 1 will have the command only try a single ping instead of an unlimited amount of time, and -t 5 sets the timeout to 5 seconds.
The echo command prints an ASCII BEL, which will cause your terminal to emit an alert sound. Of course, you could use any other command here, for example to send you an email, use the OS notification system, or whatever else you can come up with!

If, on the other hand, you maybe are more concerned with avoiding other people and want to be notified once your roommate leaves so you can get a glass of water without running into anyone, the logic can easily be reversed:

while ping -c 1 -t 5 192.168.178.1
do
  sleep 1
done
echo '\007'

This will beep once the ping command fails.