Often we want to run the same sequence of commands, over and over again, with slight differences. For example, suppose that we want to take all files named *.txt and rename them to *.txt.bak ("backup"). We can use file-expansion to get the list of files named *.txt, but how do we use that list? There's no obvious command containing, say, 'foo.txt' 'bar.txt' 'baz.txt', that would perform the three moves we need. What we need is a for loop:

for file in *.txt ; do
  mv "$file" "$file.bak"
done

The above takes the variable file, and assigns it in turn to each word in the expansion of *.txt. Each time, it runs the body of the loop. In other words, it is equivalent to the following:

file='foo.txt'
mv "$file" "$file.bak"
file='bar.txt'
mv "$file" "$file.bak"
file='baz.txt'
mv "$file" "$file.bak"

There is nothing special here about filename expansion; we can use the same approach to iterate over any other argument-list, such as the integers 1 through 20 (using brace expansion):

for i in {1..20} ; do
  echo "$i"
done

or the positional parameters "$@":

for arg in "$@" ; do
  echo "$arg"
done

In fact, that specific case is so common that Bash provides the equivalent shorthand for arg ; do, with in "$@" being implied. (But it's probably better to use the explicit form anyway.)

Another kind of loop is the while loop. It is similar to an if statement, except that it loops repeatedly as long as its test-command continues to be successful. For example, suppose that we need to wait until the file wait.txt is deleted. One approach is to "sleep" for a few seconds, then "wake up" and see if it still exists. We can loop repeatedly in this fashion:

while [[ -e wait.txt ]] ; do
  sleep 3 # "sleep" for three seconds
done

Conversely, we can use an until loop to loop until a given command is successful; for example, the reverse of the above might be:

until [[ -e proceed.txt ]] ; do
  sleep 3 # "sleep" for three seconds
done

Of course, this is the same as combining while with !, but in some cases it may be more readable.

  • Just like if, while judges true or false in the same way. Try it out yourself.