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.