Sometimes a command can only succeed when certain conditions are met. For example, you can only download a file after the file is created. In such cases, one might want to run a command repeatedly until it succeeds.
Running a command until it succeeds
How to do it...
Define a function in the following way:
repeat() { while true do $@ && return done }
Alternatively, add this to your shell's rc file for ease of use:
repeat() { while true; do $@ && return; done }
How it works...
This repeat function has an infinite while loop, which attempts to run the command passed as a parameter (accessed by $@) to the function. It returns if the command was successful, thereby exiting the loop.
There's more...
We saw a basic way to run commands until they succeed. Let's make things more efficient.
A faster approach
On most modern systems, true is implemented as a binary in /bin. This means that each time the aforementioned while loop runs, the shell has to spawn a process. To avoid this, we can use the shell built-in : command, which always returns an exit code 0:
repeat() { while :; do $@ && return; done }
Though not as readable, this is faster than the first approach.
Adding a delay
Let's say you are using repeat() to download a file from the Internet which is not available right now, but will be after some time. An example would be as follows:
repeat wget -c http://www.example.com/software-0.1.tar.gz
This script will send too much traffic to the web server at www.example.com, which causes problems for the server (and maybe for you, if the server blacklists your IP as an attacker). To solve this, we modify the function and add a delay, as follows:
repeat() { while :; do $@ && return; sleep 30; done }
This will cause the command to run every 30 seconds.