Tuesday, November 22, 2011

Shell Script Errors. Part2. Control Structures

Pitfalls of shell scripting. Part2

Control structures

If statement

  • General programming languages provide the ability to add conditions after the if command, but in shell scripting one cannot give conditions as it is. 
  • It has to be a command and the EXIT VALUE of the command is used in the if condition testing. 
  • If the command returned a 0, meaning successful completion, it goes to the "then" block, for all other VALUES, it moves to the next line of the "then" statement.
  • There can be more than one commands on the if line, and all of them are executed in the order they are specified but the exit code of the last command alone is used to check the "if" condition. This can be a source of common error.
  • There can be an "elif" statement(equivalent to the generic-else if), an "else" statement(which should, of course be the last conditional). 
  • But there has to be a "fi" statement at the end of the "if" block. 
  • One cannot put simple checks, like we do in other programming languages, on the "if" line. It has to be a command. So for operations like

    $var1 is greater than $var2,

we have to use the test command, which evaluates an expression and stores the true value as 0, and false as 1.
    So we have to use this command to get around checks in the "if" block.
    eg., if test $var1 -gt $var2

  • There is a better substitute for the test command, which reduces typing and makes code more readable. [ ] operator is of use here.

    eg., if [ $var -gt $var2 ]

  • One hugely important point to note here that there should be a space after the opening brace and a space between the last character and the closing brace. This is a huge source of common error.

    There are 3 classes of tests available in UNIX shell scripting.

1. Numeric comparisons

Less Than-lt$var1 -lt $var2
Greater Than-gt$var1 -gt $var2
Less Than Equal to-le$var1 -le $var2
Greater Than Equal to-ge$var1 -ge $var2
Equal to-eq$var1 -eq $var2
Not Equal to-ne$var1 -ne $var2

  • One notable shortcoming of the bash shell is that it cannot handle anything other than integers. So this operation would give an error.
      var1=`bc << 10/3`
      if [ $var1 -gt 3 ]
        echo something

It will give an error in the comparison statement as var1 is 3.33 and it expects an integer. And there is no work-around this. :-(

2.String comparisons

Greater Than>$var1 > $var2
Less Than<$var1 < $var2
Equal to=$var1 = $var2
Not Equal to!=$var1 != $var2

  • Note that the equality test is only a single "=" unlike most other programming languages.
  • Also note that one has to escape the ">" & "<" characters with the normal backslash(\) otherwise the shell treats them as the file redirection operators.
    There are 2 handy operations available for strings
      -n = Tests if a string has length greater than 0.
      -z = Tests if a string has 0 length.

    if [ -n $var1 ] # Returns true
    if [ -z $var2 ] # Returns true

    3. File comparisons
      This kind of comparison is useful for files and directories manipulation 

Check if file exists and is a file-f-f file1
Check if file exists and is a directory-d-d file1
Check if file exists-e-e file1
Check if file is writable-w-w file1
Check if file is readable-r-r file1
Check if file is executable-x-x file1
Check if file1 is newer than file2-ntfile1 -nt file2
Check if file1 is older than file2-otfile1 -ot file2

Compound condition testing
  The normal [ ]  style can also handle multiple testing operations. 

   eg., [ $var1 -gt $var2 ] && [ $var3 -le $var4 ]

  The curious reader might observe that it comes handy while operating on files as one would like to test if a file exists and is writable before attempting to write to it. This makes the program more robust as it fails hard and loudly when something is not as it expected, which is a desirable design policy.

  eg., if [ -f $file1 ] && [ -w $file1 ]

checks if the file in variable file1 is a file and exists and is writable?

    There are 2 variations of the [ ]  operation.
      1. [[ ]] This is useful for string comparisons because it provides the ability for pattern matching.
      eg., if [[ -e /folder/file* ]]
      2. (( )) this is useful for numeric comparisons as it can perform complex operations like **(exponentiation), <<, >> (bitwise operations for shifting), &, | (bitwise operations for logical comparisons) etc.

case command

  the syntax for case command is

  case variable in
  pattern1 | pattern2 ... | patternN) command_Set1;;
  patternX) command_Set2;;
  *) default commands;;

  One good thing is that one can list multiple cases separating them with the "|" operator together.

  case $v in
  [0-5])echo lower half nos
        echo "skipping the rest";;
  [5-8])echo higher half nos
        echo "skipping the rest";;
  *)echo "It is 9!!!!";;

  Observe that the set of commands are to be listed as is. the ";;" symbol is to appear only at the end of the command set.

No comments:

Post a Comment