Tuesday, November 22, 2011

shell script errors. Part3. Looping constructs


Pitfalls of shell scripting. Part 3

Looping constructs.

FOR

  for var in list
  do
    commands
  done

  • list can be a space separated set of values on which we want to operate. 
  • One limitation here is any word that has a space in it has to be enclosed in double quotes("") for the shell to treat them as a single element in the list.
  • The power of this loop is that the list does not have to be hard coded. It can be the output of a command.
  eg.,
 
  for word in I don\'t know if "this'll" work
  do
    echo "WORD = $word"
  done
 

  OR
 
  list="word1 word2 word3 word4"
  list=$list" word5"
  for word in $list
  do
    echo "WORD = $word"
  done
 

  Observe the second line of the listing. This is how concatenation happens in shell scripting.

  OR
 
  for word in `cat words`
  do
    echo "WORD = $word"
  done

  • A problem here or with any of the above methods is that if the file or the listing has spaces, newlines, etc. every space separated value will be considered an individual element and processed separately, while this is not we wanted.
  • The reason here is something more internal to UNIX. In Unix, there is something called the "Internal Field Separator(IFS)" which determines what identifier acts as the delimiter. 
  • By default IFS is set to white space, tab and a newline. So when it encounters any one of them the next stuff becomes a separate element.
  • If in our case we want each newline alone to be considered an element, we will have to set the IFS to "\n" explicitly before processing the for loop.
  IFS=$'\n'
  for word in `cat words`
  ...
 

  Anything more than one character has to follow this syntax,
  IFS=$[characters]
  otherwise, one can write simply
  IFS=:
  if we only want the ":" to be the field separator.

  Read this post to find out some effective programs with this technique.

  There is also a C-style for loop, kept in order to allow C-programmers to be at ease. :-)

  for (( variable assignment; condition; iteration process ))
  eg.,

  for (( a = 1, b=8; a
 

  This has multiple advantages over the normal for loop.
  1. Spaces are allowed between variable assignment. (unlike the traditional style like THIS)
  2. Multiple variables can be initialized.
  3. Accessing variables doesn't require a dollar($) sign.

WHILE

  This is also a similar construct like the FOR loop.
 
  while test command
  do
    commands
  done
 

  The key to the while loop is that the command being tested on the first line has to change over the course of the loop, else it will be an infinite loop.
  eg.,
 
  while [ $var1 -gt 10 ]
  do
    echo "Something"
    var1=$[ $var1 + 2 ]
  done
 

Like IF, only the exit status of the last command on the first line is used to evaluate the loop's running.

Controlling the loop
  • Extending the traditional programming styles, bash also provides the two commands "break" and "continue", which serve pretty much the same function as their counterparts in other famous languages.
  • One additional feature of both this commands is they can be told to break "n" levels in cases of multiple nesting ( where the current level of nesting is n = 1 ). Consider this example. 
  for (( a = 1; a < 4; a++ ))
  do
    echo "Outer: $a"
    for (( b = 1; b < 5; b++ ))
    do
      echo "Inner: $b"
      if [ $b -gt 3 ]
      then
        break 2 # tells to break 2 levels.
      fi
    done
  done

  This will give:

  Outer: 1
  Inner: 1
  Inner: 2
  Inner: 3
  Inner: 4
 

Since it breaks the outer loop the whole execution stops. Similarly "continue" can also be used.

Processing output of loops

There is one small piece of beauty in the looping constructs. Instead of echo-ing things from within the loop, one can decide to write them to a file or pipe to a command.

  eg.,
 
  for file in /home/user/*
  do
    if [ -d "$file" ]
    then
      echo "$file is a directory"
    else
      echo "$file is a file"
    fi
  done > fileList.txt
 

  Instead of printing the output, it will write all of it to the file mentioned at the end of the loop.

No comments:

Post a Comment