Operating System‎ > ‎Linux‎ > ‎Linux Shell Script‎ > ‎

04. Selection and Looping (Part 2)

while
  • The while loop repeats a block of command as long as a condition is true
  • Format:
while  [  conditional expression  ]
do
        commands
done
  • You can use  [[  ]]  or  ((  ))  in place of  [ ] 
  • The shell runs the loop in this order:
  • Evaluate the conditional expression 
    • If it evaluates to false, skip the command block and go to the command that is after done (the loop is finished)
    • If it evaluates to true, then run the commands once
  • Loop back and evaluate the conditional expression again
  • Note that the condition is evaluated in the first step, so it is possible that the loop does not run at all if the condition is false at the beginning
  • It is recommended that you keep the indentation as shown 
  • Example
num=10
while  [[ $num –ge  0 ]] # while num >= 0
do
        echo  $num            # print num
        (( num-- ))               # then decrement num
done
echo ‘Blast off!’             # After printing the countdown 
                                        # sequence, print Blast off!

until

  • The until loop repeats a block of command until a condition is true
  • Format: until  [  conditional expression  ]
do
        commands
done
  • You can use  [[  ]]  or  ((  ))  in place of  [ ] 
  • The shell runs the loop in this order:
  • Evaluate the conditional expression 
    • If it evaluates to true, skip the command block and go to the command that is after done (the loop is finished)
    • If it evaluates to false, then run the commands once
  • Loop back and evaluate the conditional expression again
  • Note that the condition is evaluated in the first step, so it is possible that the loop does not run at all if the condition is true at the beginning
  • It is recommended that you keep the indentation as shown
  • Example
until  (( num ==  0 ))                          # until num is 0
do
        read –p “number to square (0 to stop) : ” num   # prompt for num
        (( num = num * num))                                            # square num
        echo $num                                                            # print square
done

for  in

  • The for in loop iterates over an argument list. For every element in the list, it runs the loop one time
  • Format:
for  element  in  list
do
        commands
done
  • With every pass of the loop, each element in the list is stored in the variable element. The commands usually access element to do some work with it
  • It is recommended that you keep the indentation as shown 
  • Examples
for  file  in  ~ # for each file in the home directory
do
        ls –F $file # list each file
done

for  num  in  1 3 5 7 9
do
        echo $num # will print 1,3,5,7,9 on separate lines
done

Nested Loop Constructs

  • All loop statements can be nested. Within each loop there can be another loop
  • Selection and loop statements can also be nested together. Within a selection block of commands there can be a loop. Likewise, within a block of commands for a loop, there can be selection statements
  • For example, what does the following code do?
count=0
for  file  in  *
do
        if  [ -f  $file ]
        then
                (( count ++ ))
        fi
done
echo  $count regular files

break

  • The break statement stops any of the 3 loops 
  • When execution reaches break, it jumps to the command after the loop and the loop is finished
  • break is typically part of an if construct because you want to stop the loop only when a certain condition is true
  • Using break can create hard to maintain code because the loop control is being ignored when execution breaks out of the loop
  • For example:
for  num  in 1 2 3 4 5 6 7 8     # looks like the loop runs 8 times
do
        echo $num
        if [ $num –eq 5 ]
        then
            break                     # but, surprise, it actually runs 5 times
        fi
done
  • For this reason, you should think twice about using break to stop a loop. If there is a condition that should cause a break in the loop, then that condition should be part of the loop control condition.
  • In the example above,  for  num  in 1 2 3 4 5  would be much better coding practice

continue

  • The continue statement causes execution to skip the current iteration of the loop and go on to the next iteration
  • When execution reaches continue, it jumps to the top of the loop and starts the next iteration of the loop
  • continue is typically part of an if construct because you want to skip an iteration only when a certain condition is true
  • Using continue can create hard to maintain code because the loop control is being ignored when execution skips an iteration
  • For example
for  num  in 1 2 3 4 5 6 7 8 # even though the loop goes from 1 to 8
do
        if [ $num –eq 5 ]
        then
            continue # 5 will not get printed
        fi
        echo $num
done
  • For this reason, continue should be used only when checking for an error condition and the loop should not run for the iteration that has the error
 

Debugging

  • The shell provides a –x option to help you debug your script
  • When the –x option is turned on, the shell prints the command in the script before it runs that command 
    • This can help you see all the iterations of a loop and all the decision making with an if construct
  • To turn the –x option on, put   set  –x   in your script where you want the shell to start printing the command
    • To turn the –x option off, put   set  +x   in your script where you want the shell to stop printing the command
    • By using –x and +x options, you can isolate the part of the script that you want to debug
  • When debug mode is set and the shell prints the command, it adds a + symbol in front of the command, to make it easier for you to differentiate between a command that’s being printed and the script output that’s being printed.
  • If you want to change the + symbol to something else, change the environment variable PS4. Make sure you also export it so the bash child process that’s interpreting your script can inherit the changed PS4 value
  • In addition to the –x option, there are some common debugging techniques that programmers should always use
    • Write one logical block of code at a time, then test and debug it until it works before adding more code. Writing an entire script without incremental debugging is just asking for a headache!
    • Don’t underestimate the power of the echo utility to print out variable values. Printing intermediate values is one of the classic and most often used debugging techniques

If you use vi as your text editor, here are some basic tips to make coding and debugging easier.

  • The command:   nG
    • means vi will go to line n. This is useful when the error is on line n and you want to get there fast
  • The repeat command:   .     (a single period)
    • is to repeat the previous command that changes text. This is useful when you need to make the same change in several places in your code
  • The substitute command works just like the sed s command and will accept regular expressions as well as \t and \n escape characters
  • The command    :set  number 
    • means vi will show line numbers along with your code. This is very useful when the error message refers to a certain line number
  • The command    :set  ts=2
    • means that when you hit the tab key, it will indent by 2 spaces.
    • Indenting is important in making code readable, and most programmers prefer to use the tab key rather than hitting the space bar several times to get the same effect.
    • The default value for tab in vi is 5 spaces and I find that 5 is too much indentation, especially when there are nested blocks of code. Therefore you can adjust the tab spacing something smaller than 5.
  • The 2 set commands only last for the current vi session, so when you log out, the setting is gone.
    • To make the setting last across sessions, create a hidden file called .exrc in your home directory. In that file, enter the 2 set commands without the preceding : and with one command per line. When you run vi the next time, the setting will take effect.


Comments