Advanced Bash-Scripting Guide(三)

Advanced Bash-Scripting Guide(三)

Chapter 11. Loops and Branches
        • for loops
           for arg in [list]
             This is the basic looping construct. It differs significantly from its C counterpart.
           for arg in [list]
           do
            command(s)...
           done
             During each pass through the loop, arg takes on the value of each successive variable in the list.
           # The argument list may contain wild cards.
         . Arguments in [list] quoted to prevent possible word splitting.
           for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto
           do
             echo $planet  # Each planet on a separate line.
           done
           for planet in "Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto"
               # All planets on same line.
               # Entire 'list' enclosed in quotes creates a single variable.
               # Why? Whitespace incorporated into the variable.
           do
             echo $planet
           done
         . Each [list] element may contain multiple parameters. This is useful when processing parameters
           in groups. In such cases, use the set command (see Example 15-16) to force parsing of each [list]
           element and assignment of each component to the positional parameters.
           # Associate the name of each planet with its distance from the sun.
           for planet in "Mercury 36" "Venus 67" "Earth 93" "Mars 142" "Jupiter 483"
           do
           set -- $planet # Parses variable "planet"
           #+ and sets positional parameters.
           # The "--" prevents nasty surprises if $planet is null or
           #+ begins with a dash.
           # May need to save original positional parameters,
           #+ since they get overwritten.
           # One way of doing this is to use an array,
           # original_params=("$@")
           echo "$1 $2,000,000 miles from the sun"
           #-------two tabs---concatenate zeroes onto parameter $2
           done
         . If the [list] in a for loop contains wild cards (* and ?) used in filename expansion, then globbing
           takes place.
           for file in *
           # ^ Bash performs filename expansion
           #+ on expressions that globbing recognizes.
           do
           ls -l "$file"| awk '{ print $8 " file size: " $5 }' # Lists all files in $PWD (current directory) and Print 2 fields..
           # Recall that the wild card character "*" matches every filename,
           #+ however, in "globbing," it doesn't match dot-files.
           # If the pattern matches no file, it is expanded to itself.
           # To prevent this, set the nullglob option
           #+ (shopt -s nullglob).
           done
           echo; echo
           for file in [jx]*
           do
           rm -f $file # Removes only files beginning with "j" or "x" in $PWD.
           echo "Removed file \"$file\"".
           done
           echo
           Advanced Bash-Scripting Guide
           Chapter
         . Omitting the in [list] part of a for loop causes the loop to operate on $@ -- the positional
           parameters.
           #!/bin/bash
           # Invoke this script both with and without arguments,
           #+ and see what happens.
           for a
           do
           echo -n "$a "
           done
           # The 'in list' missing, therefore the loop operates on '$@'
           #+ (command-line argument list, including whitespace).
           echo
           exit 0
         . It is possible to use command substitution to generate the [list] in a for loop.                 
           NUMBERS="9 7 3 8 37.53"
           for number in `echo $NUMBERS` # for number in 9 7 3 8 37.53
           do
           echo -n "$number "
           done
           echo
           Example 11-8. Listing all users on the system
           #!/bin/bash
           # userlist.sh
           PASSWORD_FILE=/etc/passwd
           n=1 # User number
           for name in $(awk 'BEGIN{FS=":"}{print $1}' < "$PASSWORD_FILE" )
           # Field separator = : ^^^^^^
           # Print first field ^^^^^^^^
           # Get input from password file ^^^^^^^^^^^^^^^^^
           do
           echo "USER #$n = $name"
           let "n += 1"
           done
           # USER #1 = root
           # USER #2 = bin
           # USER #3 = daemon
           # ...
           # USER #30 = bozo
         . A final example of [list] / command substitution, but this time the "command" is a function.                                                                                                                                                                            
           generate_list ()
           {
           echo "one two three"
           }
           for word in $(generate_list) # Let "word" grab output of function.
           do
           echo "$word"
           done
           # one
           # two
           # three
         . Example 11-12. A C-style for loop                                                                           
           # +==========================================+
           # Now, let's do the same, using C-like syntax.
           LIMIT=10
           for ((a=1; a <= LIMIT ; a++)) # Double parentheses, and "LIMIT" with no "$".
           do
           echo -n "$a "
           done # A construct borrowed from 'ksh93'.
           echo; echo
           # +=========================================================================+
           # Let's use the C "comma operator" to increment two variables simultaneously.
           for ((a=1, b=1; a <= LIMIT ; a++, b++))
           do # The comma chains together operations.
           echo -n "$a-$b "
           done
           echo; echo
        • while
           This construct tests for a condition at the top of a loop, and keeps looping as long as that condition is true (returns a 0 exit status).
           while [ condition ]
           do
           command(s)...
           done
           The bracket construct in a while loop is nothing more than our old friend, the test brackets used in an
           if/then test. In fact, a while loop can legally use the more versatile double-brackets construct (while [[ condition ]]).
           A while loop may have multiple conditions. Only the final condition determines when the loop
           terminates. This necessitates a slightly different loop syntax, however.
           #!/bin/bash
           var1=unset
           previous=$var1
           while echo "previous-variable = $previous"
           echo
           previous=$var1
           [ "$var1" != end ] # Keeps track of what $var1 was previously.
           # Four conditions on "while", but only last one controls loop.
           # The *last* exit status is the one that counts.
           do
           echo "Input variable #1 (end to exit) "
           read var1
           echo "variable #1 = $var1"
           done
         . As with a for loop, a while loop may employ C-style syntax by using the double-parentheses construct   
           #!/bin/bash
           # wh-loopc.sh: Count to 10 in a "while" loop.
           LIMIT=10 # 10 iterations.
           a=1
           while [ "$a" -le $LIMIT ]
           do
           echo -n "$a "
           let "a+=1"
           done # No surprises, so far.
           echo; echo
           # +=================================================================+
           # Now, we'll repeat with C-like syntax.
           ((a = 1)) # a=1
           # Double parentheses permit space when setting a variable, as in C.
           while (( a <= LIMIT )) # Double parentheses,
           do #+ and no "$" preceding variables.
           echo -n "$a "
           ((a += 1)) # let "a+=1"
           # Yes, indeed.
           # Double parentheses permit incrementing a variable with C-like syntax.
           done
         . Inside its test brackets, a while loop can call a function.                                          
           t=0
           condition ()
           {
           ((t++))
           if [ $t -lt 5 ]
           then
           return 0 # true
           else
           return 1 # false
           fi
           }
           while condition
           # ^^^^^^^^^
           # Function call -- four loop iterations.
           do
           echo "Still going: t = $t"
           done
         . By coupling the power of the read command with a while loop, we get the handy while read construct,
           useful for reading and parsing files.
           cat $filename | # Supply input from a file.
           while read line # As long as there is another line to read ...
           do
           ...
           done
           # =========== Snippet from "sd.sh" example script ========== #
           while read value # Read one data point at a time.
           do
           rt=$(echo "scale=$SC; $rt + $value" | bc)
           (( ct++ ))
           done
           am=$(echo "scale=$SC; $rt / $ct" | bc)
           echo $am; return $ct # This function "returns" TWO values!
           # Caution: This little trick will not work if $ct > 255!
           # To handle a larger number of data points,
           #+ simply comment out the "return $ct" above.
           } <"$datafile" # Feed in data file.
         . A while loop may have its stdin redirected to a file by a < at its end.
         . A while loop may have its stdin supplied by a pipe.
        • until
           This construct tests for a condition at the top of a loop, and keeps looping as long as that condition is
           false (opposite of while loop).
           until [ condition-is-true ]
           do
           command(s)...
           done
        • break, continue
           The break and continue loop control commands [52] correspond exactly to their counterparts in other
           programming languages. The break command terminates the loop (breaks out of it), while continue
           causes a jump to the next iteration of the loop, skipping all the remaining commands in that particular
           loop cycle.
         . The break command may optionally take a parameter. A plain break terminates only the innermost
           loop in which it is embedded, but a break N breaks out of N levels of loop.
           #!/bin/bash
           # break-levels.sh: Breaking out of loops.
           # "break N" breaks out of N level loops.
           for outerloop in 1 2 3 4 5
           do
           echo -n "Group $outerloop: "
           # --------------------------------------------------------
           for innerloop in 1 2 3 4 5
           do
           echo -n "$innerloop "
           if [ "$innerloop" -eq 3 ]
           then
           break # Try break 2 to see what happens.
           # ("Breaks" out of both inner and outer loops.)
           fi
           done
           # --------------------------------------------------------
           echo
           done
         . The continue command, similar to break, optionally takes a parameter. A plain continue cuts short
           the current iteration within its loop and begins the next. A continue N terminates all remaining
           iterations at its loop level and continues with the next iteration at the loop, N levels above.
           #!/bin/bash
           # The "continue N" command, continuing at the Nth level loop.
           for outer in I II III IV V # outer loop
           do
           echo; echo -n "Group $outer: "
           # --------------------------------------------------------------------
           for inner in 1 2 3 4 5 6 7 8 9 10 # inner loop
           do
           if [[ "$inner" -eq 7 && "$outer" = "III" ]]
           then
           continue 2 # Continue at loop on 2nd level, that is "outer loop".
           # Replace above line with a simple "continue"
           # to see normal loop behavior.
           fi
           echo -n "$inner " # 7 8 9 10 will not echo on "Group III."
           done
           # --------------------------------------------------------------------
           done
       •  Testing and Branching                                                                                  
         . case (in) / esac
           The case construct is the shell scripting analog to switch in C/C++. It permits branching to one of a
           number of code blocks, depending on condition tests. It serves as a kind of shorthand for multiple
           if/then/else statements and is an appropriate tool for creating menus.
           case "$variable" in
           "$condition1" )
           command...
           ;;
           "$condition2" )
           command...
           ;;
           esac
           # Quoting the variables is not mandatory, since word splitting does not take place.
           # Each test line ends with a right paren ). [53]
           # Each condition block ends with a double semicolon ;;.
           # If a condition tests true, then the associated commands execute and the case block terminates.
           # The entire case block ends with an esac (case spelled backwards).
           #!/bin/bash
           # Testing ranges of characters.
           echo; echo "Hit a key, then hit return."
           read Keypress
           case "$Keypress" in
           [[:lower:]] ) echo "Lowercase letter";;
           [[:upper:]] ) echo "Uppercase letter";;
           [0-9] ) echo "Digit";;
           * ) echo "Punctuation, whitespace, or other";;
           esac # Allows ranges of characters in [square brackets],
           #+ or POSIX ranges in [[double square brackets.
         . An exceptionally clever use of case involves testing for command-line parameters.                 
           #! /bin/bash
           while [ $# -gt 0 ]; do # Until you run out of parameters . . .
           case "$1" in
           -d|--debug)
           # "-d" or "--debug" parameter?
           DEBUG=1
           ;;
           -c|--conf)
           CONFFILE="$2"
           shift
           if [ ! -f $CONFFILE ]; then
           echo "Error: Supplied file doesn't exist!"
           exit $E_CONFFILE # File not found error.
           fi
           ;;
           esac
           shift # Check next set of parameters.
           done
         . A case construct can filter strings for globbing patterns.          
           #!/bin/bash
           # match-string.sh: Simple string matching.
           match_string ()
           { # Exact string match.
           MATCH=0
           E_NOMATCH=90
           PARAMS=2 # Function requires 2 arguments.
           E_BAD_PARAMS=91
           [ $# -eq $PARAMS ] || return $E_BAD_PARAMS
           case "$1" in
           "$2") return $MATCH;;
           * ) return $E_NOMATCH;;
           esac
           }
           a=one
           b=two
           c=three
           d=two
           match_string $a # wrong number of parameters
           echo $? # 91
           match_string $a $b # no match
           echo $? # 90
           match_string $b $d # match
           echo $? # 0
       •  select
           The select construct, adopted from the Korn Shell, is yet another tool for building menus.
           select variable [in list]
           do
           command...
           break
           done                     
           # This prompts the user to enter one of the choices presented in the variable list. Note that select uses
             the $PS3 prompt (#? ) by default, but this may be changed.
         . If in list is omitted, then select uses the list of command line arguments ($@) passed to the script
             or the function containing the select construct.
           #!/bin/bash
           PS3='Choose your favorite vegetable: '
           echo
           choice_of()
           {
           select vegetable
           # [in list] omitted, so 'select' uses arguments passed to function.
           do
           echo
           echo "Your favorite veggie is $vegetable."
           echo "Yuck!"
           echo
           break
           done
           }
           choice_of beans rice carrots radishes tomatoes spinach
           # $1 $2 $3 $4 $5 $6
           # passed to choice_of() function
Chapter 12.Command Substitution                     
           Command substitution reassigns the output of a command [54] or even multiple commands; it literally plugs
           the command output into another context.
           # Command substitution invokes a subshell.
         . Command substitution may result in word splitting.
           COMMAND `echo a b` # 2 args: a and b
           COMMAND "`echo a b`" # 1 arg: "a b"
           COMMAND `echo` # no arg
           COMMAND "`echo`" # one empty arg
         . Command substitution permits setting a variable to the output of a loop. The key to this is grabbing the output
           of an echo command within the loop.
           variable1=`for i in 1 2 3 4 5
           do
           echo -n "$i" # The 'echo' command is critical
           done` #+ to command substitution here.
           echo "variable1 = $variable1" # variable1 = 12345
           i=0
           variable2=`while [ "$i" -lt 10 ]
           do
           echo -n "$i" # Again, the necessary 'echo'.
           let "i += 1" # Increment.
           done`
           echo "variable2 = $variable2" # variable2 = 0123456789
         . Command substitution makes it possible to extend the toolset available to Bash. It is simply a matter of
           writing a program or script that outputs to stdout (like a well-behaved UNIX tool should) and assigning
           that output to a variable.
           #include <stdio.h>
           /* "Hello, world." C program */
           int main()
           {
           printf( "Hello, world.\n" );
           return (0);
           }
           bash$ gcc -o hello hello.c
           #!/bin/bash
           # hello.sh
           greeting=`./hello`
           echo $greeting
           bash$ sh hello.sh
           Hello, world.
Chapter 13. Arithmetic Expansion                                                  
           Arithmetic expansion provides a powerful tool for performing (integer) arithmetic operations in scripts.
           Translating a string into a numerical expression is relatively straightforward using backticks, double
           parentheses, or let.
         . Arithmetic expansion with backticks (often used in conjunction with expr)         
           z=`expr $z + 3` # The 'expr' command performs the expansion.
         . Arithmetic expansion with double parentheses, and using let
           The use of backticks (backquotes) in arithmetic expansion has been superseded by double parentheses
           -- ((...)) and $((...)) -- and also by the very convenient let construction.
           z=$(($z+3))
           z=$((z+3)) # Also correct.
           # Within double parentheses,
           #+ parameter dereferencing
           #+ is optional.
           # $((EXPRESSION)) is arithmetic expansion. # Not to be confused with
           #+ command substitution.
           # You may also use operations within double parentheses without assignment.
           n=0
           echo "n = $n" # n = 0
           (( n += 1 )) # Increment.
           # (( $n += 1 )) is incorrect!
           echo "n = $n" # n = 1
           let z=z+3
           let "z += 3" # Quotes permit the use of spaces in variable assignment.
           # The 'let' operator actually performs arithmetic evaluation,
           #+ rather than expansion.
         
 

你可能感兴趣的:(职场,bash,休闲)