We're an ISO27001:2013 Certified Supplier

Eat sleep Linux repeat

There are occasions when we want to run a series of commands repeatedly in the Linux shell and, as usual with Linux, there’s more than one way to do that.

Command Recall

The example we’re probably all familiar with is the keyboard up arrow. Each press of that key will step back through the command history (unless we’ve hidden it) and let us re-execute an earlier command.

There are a number of tricks to improve this functionality, and one of my favourites is to include this in the /etc/inputrc file:

# map "page up" and "page down" to search the history
"\e[5~": history-search-backward
"\e[6~": history-search-forward

Now, if you want to ssh to a system you have ssh‘d to before, type ssh and press the Page Up key. Each time you press it, the previous command that starts ssh will be shown.

Others prefer to type ^R followed by any part of a previous command, which will display the most recent command that matches whatever was typed after the ^R. You can step back through earlier matches by repeating ^R.

Command Recall Loops

In a somewhat contrived example, let’s suppose you are making some tweaks to an Apache site configuration file. Your most recent command line history is:

# vim /etc/apache2/sites-enabled/www.example.com.conf
# apache2ctl -t
# apache2ctl graceful

But all is not well, and you need to make a further edit. Press the up arrow to recall the vim line, then instead of pressing return, type ^O. The editor will be loaded and you can make your changes. When you return to the command line, the next command – apachectl -t – will already be loaded. Again, press ^O, which will run the command and place the last command above on the command line. If you again press ^O, bash will loop back to the vim command.

I will confess I don’t use this very much, but it seemed too interesting to ignore!

For Loops

One construction I do use a lot is for loops. Let’s suppose you have some WAVE audio files that you want to convert to mp3 files. We can achieve that with:

for a in *.wav;do ffmpeg -i $a ${a%.wav}.mp3;done

This will:

  • find each *.wav file in the current directory and assign each in turn to the bash variable a
  • run ffmpeg with the .wav file as the input

The output filename is derived from ${a%.wav}.mp3. This:

  • takes the variable a and removes from the end the shortest pattern that matches .wav, so for myfile.wav${a%.wav} will result in myfile
  • that shortened name has .mp3 appended

A useful tip when building for loops is to precede commands with echo so that you can see what will be done:

$ for a in *.wav;do echo ffmpeg -i $a ${a%.wav}.mp3;done
ffmpeg -i soundfile1.wav soundfile1.mp3
ffmpeg -i soundfile2.wav soundfile2.mp3
ffmpeg -i soundfile3.wav soundfile3.mp3
ffmpeg -i soundfile4.wav soundfile4.mp3
ffmpeg -i soundfile5.wav soundfile5.mp3
ffmpeg -i test.wav.wav test.wav.mp3

Once you’re happy with the result, you can command-recall, remove the echo and run.

Could This Linux Tip be Improved?

Let us know in the comments below.

1 thought on “Linux Tips: Repeating Commands”

Leave a Reply

Your email address will not be published. Required fields are marked *

Secure. Reliable. Scalable.

If that doesn't describe your current Linux systems, check out our FREE Linux Survival Guide to help you get your systems up to scratch today!

  • This field is for validation purposes and should be left unchanged.