Bash scripting 101: Chapter 3: For he'$ a jolly good fellow (loopy loops)





for: for NAME [in WORDS ... ;] do COMMANDS; done
    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.
is what the bash command help has to say about "for" ( help for ), not very informative is it?

rates somewhere in readability between INS and IRS i would guess (having only sampled one)

what does it mean for the shell scripter?

we'll start out simple:

#!/bin/bash

for I in 1 2 3 4 5 6 7 8 9
do

    echo -e "printing number $I \n"

done

it will print out 1-9 with a small text message..ooh try it yaselves!

why does it do this? well line by line, blow by blow below

  1. #!/bin/bash
    the ever famous SHEBANG line

  2. for I in 1 2 3 4 5 6 7 8 9
    for each and everyone of the "list" (1 2 3 4 5 6 7 8 9) put them one by one into "I", do the thing stated between "do" and "done" and then put the next thing in the list into "I" and do it again.

  3. do
    start the "for" "loop" block

  4. echo -e "printing number $I \n"
    echo/print with backslash escaped interpretation "printing number $I \n" insert the content of variable I there. i also indented (increased spaces before it) this makes subroutines and loops easier to see, increase a few spaces for each "level" (you'll see this more and more further on).

  5. done
    end the "for" "loop" block

so let's get creative with counting, can we do this with variables? but of course!

#!/bin/bash

ONE="1 2 3"
FOUR="4 5 6"
SEVEN="7 8 9"

for I in $ONE $FOUR $SEVEN
do

    echo -e "printing $I \n"

done

you did what???

i did...

  1. #!/bin/bash

  2. ONE="1 2 3"
    this one is new, i'm putting "1 2 3" into a variable called "ONE", i'm putting spaces between the number to make sure for will see them as separate numbers

  3. FOUR="4 5 6"
    see point (2) different name and values, same deal

  4. SEVEN="7 8 9"
    see point (2)

  5. for I in $ONE $FOUR $SEVEN
    this one takes a little explaining, what bash first sees is:
    for I in $ONE $FOUR $SEVEN
    then it looks over it again, cause the variables need to be looked into and it sees:
    for I in 1 2 3 $FOUR $SEVEN
    for I in 1 2 3 4 5 6 $SEVEN
    for I in 1 2 3 4 5 6 7 8 9
    it actually does all the variables in one go(i think, bash programmers please inform me if i'm wrong), i've simply separated them to illustrate the process

  6. do
    start the do/done part for loop (the looping part)

  7. echo -e "printing $I \n"
    we know this one by now

  8. done
    end the do/done part

isn't this a complex way when i can just write echo -e "1 2 3 4 5 6 7 8 9"? Yes, it is, it is an example, bear with me, and see the potential instead of my silly examples :-)

#!/bin/bash

ONE="1 2 3"
FOUR="4 5 6"
SEVEN="7 8 9"
TWELVE="$ONE $FOUR $SEVEN 10 11 12"

for I in $TWELVE
do

    echo -e "printing $I \n"

done

here comes the break down. I'll skip all lines except for the ones i've actually added or made changes to :-)

  1. TWELVE="$ONE $FOUR $SEVEN 10 11 12"
    the Variable "TWELVE" is the same as the content of variable ONE FOUR SEVEN 10 11 12
    IE. TWELVE is "1 2 3 4 5 6 7 8 9 10 11 12" notice however how easily i could mix numbers and variables

  2. for I in $TWELVE
    use the contents of variable TWELVE (see point 1) as a list of words/elements to put into I

dude didn't you say there was potential here?

yes i did and yes there is

as a person online i sometimes want to know if a host exists with a certain TLD (Top Level Domain(.com, .gov and so on)) i use a script like this:

#!/bin/bash
test "${1}" = "" && echo 'script needs at least a domain name without tld to check' && exit 1

TOPLEVELDOMAINS="edu com gov net org"

for TLD in $TOPLEVELDOMAINS
do
    host $1.$TLD
done

you can from now on just assume i'll just "break down" the lines that contain new stuff

WHOOA!!! you are really trying to give me a headache right..admit it!!!

no i'm not, it's not as bad as it looks, i promise, it's actually so simple you'll probably go "aha" and give me a look of "wasn't there more to it than that?"

  1. test "${1}" = "" && echo 'script needs at least a domain name without tld to check' && exit 1
    test is a bash-built-in command, it exits with (0) if the expression is "true" and with (1) if it's false

    1. here we are asking "test" to compare the strings "${1}" and "" (empty string),

    2. ${1} is a "referance" to "$1"

      actually it's "entry one of "$@" and $@ is a special variable (array actually(more on that later)) containing all the commandline switches given when program is called (when you type the script name)ie $@ is "$1 $2 $3..." and what ${1} does is simply ask for the "$1" entry.

    3. since that first entry is (unless you gave a hostname) empty it'll match ""

    4. if it matches "" it(test) will exit with (0)

    5. if it exits with (0) it is "true" and means that && (AND) is done

      if you remember chapter one we used "||" (OR) here is now the opposite "&&" (AND) "if the program before did OK then do THIS one too"

    6. echo '...' this one you know

    7. since echo will work almost guaranteed "&&"(AND) "exit (1)" will exit the script returning a (1) the "one" is a signal that means "i had an error, i'm exiting/stopping program".

      This is done in case you call this shell script from another shellscript and that other shellscript checks if THIS one executed properly.

  2. TOPLEVELDOMAINS="edu com gov net org"
    into variable TOPLEVELDOMAINS put the most common tld's

  3. for TLD in $TOPLEVELDOMAINS
    for each value in TOPLEVELDOMAINS, put it into TLD and

  4. do
    start the "do" block

  5. host $1.$TLD
    host is a command that looks up ip numbers from hostnames, or vice versa, what bash sees is:

    iteration 1 (first repeat)host name_you_entered_as_command_line_argument.edu
    iteration 2 (second repeat)host name_you_entered_as_command_line_argument.com
    iteration 3 (third repeat)host name_you_entered_as_command_line_argument.gov
    iteration 4 (fourth repeat)host name_you_entered_as_command_line_argument.net
    iteration 5 (fifth repeat)host name_you_entered_as_command_line_argument.org

    so why didn't i put the "." in TOPLEVELDOMAINS as in ".com .edu..." i didn't since i'm lazy, it'd be 5 "." compared to one "." in the for/do/done block

  6. done
    end do block

for you windows users out there, there is actually a way to do this too

ahhh but you see i want to look up some international tld's too!!! got ya now w0nderer don't i!!!

nope, you don't, read the next chapter :-)




Bash Scripting101: chapter 2: hello world(first real shell script) Bash Scripting101: chapter 4: IF he's jolly why is he loopy? (loopy loops)



w0nderer