For loops in bash

Iteration: it’s such a powerful tool. Automating the repetition of tasks can save so much time and keystrokes and tedium. This capability is one of the reasons I love bash, my command shell of choice. I used to employ tcsh, but switched to bash years ago mainly because most linux system scripts use bash, and I wanted to just focus on one syntax so that my own scripts and the system ones would be equally readable. But bash also opened my eyes to the beauties of command-line for loops. (Tcsh makes them interactive, which initially seems nice, but then is annoying if you’d like to re-do an earlier loop you typed in.)

So now I regularly use for loops at the command line for all sorts of things: resizing a collection of images, creating a collection of symbolic links, renaming a series of files by some standard convention. It’s great for any task in which you want to do the same operation, but the individual commands differ slightly, and in which you can’t just pass in a wildcard list of inputs. But for the longest time, I thought there was only one form of the loop syntax:

for i in choice1 choice2 … choiceN ; do
… [some task with $i, the current choice]

Thanks to this great collection of for loop examples, I’ve learned that bash now also supports sequence iteration! So you can do

for i in {1..5}; do
… [some task with $i, a number from 1 to 5] …

Previously, I would have written

for i in 1 2 3 4 5 ; do
… [some task with $i, the current choice] …

which gets very clunky with larger ranges, involving nested loops, one per digit. Ugh!

Newer bashes (version 4.0+) even support increments, e.g.

for i in {1..5..2}; do
… [some task with $i, an odd number from 1 to 5] …

And wow, there’s even a C-style syntax:

for (( i=1; i<=5; i++ )); do
… [some task with $i, a number from 1 to 5] …

For loops just got easier.

I used this today to generate a file that contained 16 1’s followed by 16 2’s followed by 16 3’s… all the way up to 16 30’s. Exactly the kind of thing I don’t want to do manually. And yes, I actually needed this file in order to get some research done. So it goes!

4 of 4 people learned something from this entry.

  1. Kevin Turner said,

    November 1, 2011 at 7:16 pm

    (Learned something new!)

    What magic is this? Apparently I need to read the news on Bash 4.0 features.

    I remember when I finally learned about /usr/bin/seq, it was a magical day.

    for i in $(seq 5) ; do echo $i fishes ; done

    but it sounds like this new syntax replaces it.

    The presence of such features in bash occasionally tempts me to do things like use bash array types, but so far that’s been a bit of a masochistic exercise every time I’ve attempted it. That is, I’ve been able to achieve the result in bash (usually), but not without considerable effort and cost to readability.

  2. Mike said,

    November 1, 2011 at 9:27 pm

    (Learned something new!)

    Not only can I now use the more familiar for loop constructs, but I also just went on an expedition to re-update my bash shell. I replaced my harddrive over the summer (which was enlightening in of itself!) and never got around to it.

    In any case, thanks for the well-warranted distraction from my homework!

  3. Kiri said,

    November 1, 2011 at 10:46 pm

    Good tip, Kevin: Looking this up was my first exposure to seq! I wish I’d known about that a while ago.

    Mike: You’re very welcome :) And congrats on the HD replacement! SSD? :)

  4. Mike said,

    November 1, 2011 at 10:55 pm

    Unfortunately, no. It wasn’t a planned replacement, so I just got a basic 250GB drive to hold me over until I replace the entire computer. It was only $40, which was really nice.

  5. Terran said,

    November 2, 2011 at 7:36 am

    (Learned something new!)

    I have used the “C style” loop in BASH, but didn’t know about the {} sequence construct. Nifty!

    Like Kevin, I have tried to use arrays in BASH, but it always ends in pain and tears. I finally concluded that if I need such functionality, it warrants promoting to perl or python…

  6. Umaa said,

    November 9, 2011 at 11:55 pm

    (Learned something new!)

    The last thing I should be doing is feed my bash addiction, but… I too did not know about the { } syntax and always used `seq`. Thanks to Mike, I now know about $(seq n)$!

Post a Comment

I knew this already. I learned something new!