Advanced Bash-Scripting Guide(二)

Advanced Bash-Scripting Guide(二)

Chapter 7. Tests
    • An if/then construct tests whether the exit status of a list of commands is 0 (since 0 means "success"
       by UNIX convention), and if so, executes one or more commands.
    • There exists a dedicated command called [ (left bracket special character). It is a synonym for test,
       and a builtin for efficiency reasons. This command considers its arguments as comparison expressions
       or file tests and returns an exit status corresponding to the result of the comparison (0 for true, 1 for
       false).
    • With version 2.02, Bash introduced the [[ ... ]] extended test command, which performs comparisons
       in a manner more familiar to programmers from other languages. Note that [[ is a keyword, not a
       command.
       Bash sees [[ $a -lt $b ]] as a single element, which returns an exit status.
    • Using the [[ ... ]] test construct, rather than [ ... ] can prevent many logic errors in scripts. For example, the
       &&, ||, <, and > operators work within a [[ ]] test, despite giving an error within a [ ] construct.
    • Arithmetic evaluation of octal / hexadecimal constants takes place automatically within a [[ ... ]] construct.
        Ex:decimal=15
           octal=017   # = 15 (decimal)
           hex=0x0f    # = 15 (decimal)
           if [ "$decimal" -eq "$octal" ]
           then
             echo "$decimal equals $octal"
           else
             echo "$decimal is not equal to $octal"       # 15 is not equal to 017
           fi      # Doesn't evaluate within [ single brackets ]!
           if [[ "$decimal" -eq "$octal" ]]
           then
             echo "$decimal equals $octal"                # 15 equals 017
           else
             echo "$decimal is not equal to $octal"
           fi      # Evaluates within [[ double brackets ]]!
           if [[ "$decimal" -eq "$hex" ]]
           then
             echo "$decimal equals $hex"                  # 15 equals 0x0f
           else
             echo "$decimal is not equal to $hex"
           fi      # [[ $hexadecimal ]] also evaluates!
    • Following an if, neither the test command nor the test brackets ( [ ] or [[ ]] ) are strictly necessary.
    • The "if COMMAND" construct returns the exit status of COMMAND.
    • Similarly, a condition within test brackets may stand alone without an if, when used in combination with
       a list construct.
       Ex:var1=20
       var2=22
       [ "$var1" -ne "$var2" ] && echo "$var1 is not equal to $var2"
       home=/home/bozo
       [ -d "$home" ] || echo "$home directory does not exist."
    • The (( ... )) and let ... constructs return an exit status, according to whether the arithmetic expressions
       they evaluate expand to a non-zero value. These arithmetic-expansion constructs may therefore be
       used to perform arithmetic comparisons.
       Ex:# The (( ... )) construct evaluates and tests numerical expressions.
          # Exit status opposite from [ ... ] construct!
          (( 0 ))
          echo "Exit status of \"(( 0 ))\" is $?."         # 1
          (( 1 ))
          echo "Exit status of \"(( 1 ))\" is $?."         # 0
          (( 5 > 4 ))                                      # true
          echo "Exit status of \"(( 5 > 4 ))\" is $?."     # 0
          (( 5 > 9 ))                                      # false
          echo "Exit status of \"(( 5 > 9 ))\" is $?."     # 1
          (( 5 == 5 ))                                     # true
          echo "Exit status of \"(( 5 == 5 ))\" is $?."    # 0
          # (( 5 = 5 ))  gives an error message.
          (( 5 - 5 ))                                      # 0
          echo "Exit status of \"(( 5 - 5 ))\" is $?."     # 1
          (( 5 / 4 ))                                      # Division o.k.
          echo "Exit status of \"(( 5 / 4 ))\" is $?."     # 0
          (( 1 / 2 ))                                      # Division result < 1.
          echo "Exit status of \"(( 1 / 2 ))\" is $?."     # Rounded off to 0.
                                                           # 1
          (( 1 / 0 )) 2>/dev/null                          # Illegal division by 0.
          #           ^^^^^^^^^^^
          echo "Exit status of \"(( 1 / 0 ))\" is $?."     # 1
          # What effect does the "2>/dev/null" have?
          # What would happen if it were removed?
          # Try removing it, then rerunning the script.
          # ======================================= #
          # (( ... )) also useful in an if-then test.
          var1=5
          var2=4
          if (( var1 > var2 ))
          then #^      ^      Note: Not $var1, $var2. Why?
            echo "$var1 is greater than $var2"
          fi     # 5 is greater than 4
          exit 0

    • The (( )) construct expands and evaluates an arithmetic expression. If the expression evaluates as zero, it
       returns an exit status of 1, or "false". A non-zero expression returns an exit status of 0, or "true". This is in
       marked contrast to using the test and [ ] constructs previously discussed.
       
       (( 0 && 1 ))                 # Logical AND
       echo $?     # 1     ***
       # And so ...
       let "num = (( 0 && 1 ))"
       echo $num   # 0
       # But ...
       let "num = (( 0 && 1 ))"
       echo $?     # 1     ***

       (( 200 || 11 ))              # Logical OR
       echo $?     # 0     ***
       # ...
       let "num = (( 200 || 11 ))"
       echo $num   # 1
       let "num = (( 200 || 11 ))"
       echo $?     # 0     ***

       (( 200 | 11 ))               # Bitwise OR
       echo $?                      # 0     ***
       # ...
       let "num = (( 200 | 11 ))"
       echo $num                    # 203
       let "num = (( 200 | 11 ))"
       echo $?                      # 0     ***
       # The "let" construct returns the same exit status
       #+ as the double-parentheses arithmetic expansion.

    • An if can test any command, not just conditions enclosed within brackets.
       Ex:if cmp a b &> /dev/null  # Suppress output.
          then echo "Files a and b are identical."
          else echo "Files a and b differ."
          fi
          # The very useful "if-grep" construct:
          # -----------------------------------
       Ex:if grep -q Bash file
            then echo "File contains at least one occurrence of Bash."
          fi
       Ex: word=Linux
           letter_sequence=inu
           if echo "$word" | grep -q "$letter_sequence"
           # The "-q" option to grep suppresses output.
           then
             echo "$letter_sequence found in $word"
           else
             echo "$letter_sequence not found in $word"
           fi

     Example 7-1. What is truth?
           #!/bin/bash
           #  Tip:
           #  If you're unsure of how a certain condition would evaluate,
           #+ test it in an if-test.
           echo
           echo "Testing \"0\""
           if [ 0 ]      # zero
           then
             echo "0 is true."
           else          # Or else ...
             echo "0 is false."
           fi            # 0 is true.

           echo
           echo "Testing \"1\""
           if [ 1 ]      # one
           then
             echo "1 is true."
           else
             echo "1 is false."
           fi            # 1 is true.

           echo
           echo "Testing \"-1\""
           if [ -1 ]     # minus one
           then
             echo "-1 is true."
           else
             echo "-1 is false."
           fi            # -1 is true.

           echo
           echo "Testing \"NULL\""
           if [ ]        # NULL (empty condition)
           then
             echo "NULL is true."
           else
             echo "NULL is false."
           fi            # NULL is false.

           echo
           echo "Testing \"xyz\""
           if [ xyz ]    # string
           then
             echo "Random string is true."
           else
             echo "Random string is false."
           fi            # Random string is true.

           echo
           echo "Testing \"\$xyz\""
           if [ $xyz ]   # Tests if $xyz is null, but...
                         # it's only an uninitialized variable.
           then
             echo "Uninitialized variable is true."
           else
             echo "Uninitialized variable is false."
           fi            # Uninitialized variable is false.

           echo
           echo "Testing \"-n \$xyz\""
           if [ -n "$xyz" ]            # More pedantically correct.
           then
             echo "Uninitialized variable is true."
           else
             echo "Uninitialized variable is false."
           fi            # Uninitialized variable is false.

           echo
           xyz=          # Initialized, but set to null value.
           echo "Testing \"-n \$xyz\""
           if [ -n "$xyz" ]
           then
             echo "Null variable is true."
           else
             echo "Null variable is false."
           fi            # Null variable is false.

           echo
           # When is "false" true?
           echo "Testing \"false\""
           if [ "false" ]              #  It seems that "false" is just a string.
           then
             echo "\"false\" is true." #+ and it tests true.
           else
             echo "\"false\" is false."
           fi            # "false" is true.

           echo
           echo "Testing \"\$false\""  # Again, uninitialized variable.
           if [ "$false" ]
           then
             echo "\"\$false\" is true."
           else
             echo "\"\$false\" is false."
           fi            # "$false" is false.
                         # Now, we get the expected result.
           #  What would happen if we tested the uninitialized variable "$true"?
           echo
           exit 0
                
    • Elif:elif is a contraction for else if. The effect is to nest an inner if/then construct within an outer one.
              if [ condition1 ]
              then
                 command1
                 command2
                 command3
              elif [ condition2 ]
          # Same as else if
          then
             command4
             command5
          else
             default-command
          fi

Chapter 8. Operations and Related Topics    
    •  Example 8-2. Using Arithmetic Operations
        #!/bin/bash
        # Counting to 11 in 10 different ways.
        n=1; echo -n "$n "
        let "n = $n + 1"   # let "n = n + 1"  also works.
        echo -n "$n "

        : $((n = $n + 1))
        #  ":" necessary because otherwise Bash attempts
        #+ to interpret "$((n = $n + 1))" as a command.
        echo -n "$n "
        (( n = n + 1 ))
        #  A simpler alternative to the method above.
        #  Thanks, David Lombard, for pointing this out.
        echo -n "$n "

        n=$(($n + 1))
        echo -n "$n "

        : $[ n = $n + 1 ]
        #  ":" necessary because otherwise Bash attempts
        #+ to interpret "$[ n = $n + 1 ]" as a command.
        #  Works even if "n" was initialized as a string.
        echo -n "$n "

        n=$[ $n + 1 ]
        #  Works even if "n" was initialized as a string.
        #* Avoid this type of construct, since it is obsolete and nonportable.
        #  Thanks, Stephane Chazelas.
        echo -n "$n "

        # Now for C-style increment operators.
        # Thanks, Frank Wang, for pointing this out.
        let "n++"          # let "++n"  also works.
        echo -n "$n "
        (( n++ ))          # (( ++n ))  also works.
        echo -n "$n "
        : $(( n++ ))       # : $(( ++n )) also works.
        echo -n "$n "
        : $[ n++ ]         # : $[ ++n ] also works
        echo -n "$n "
        echo
        exit 0
       
   •  Bash does not understand floating point arithmetic. It treats numbers containing a decimal point as strings.
        Ex:a=1.5
           let "b = $a + 1.3"  # Error.
           # t2.sh: let: b = 1.5 + 1.3: syntax error in expression
           #                            (error token is ".5 + 1.3")
           echo "b = $b"       # b=1
           Use bc in scripts that that need floating point calculations or math library functions.
          
   •  Numerical Constants:
           Example 8-4. Representation of numerical constants                      
           #!/bin/bash
           # numbers.sh: Representation of numbers in different bases.
           # Decimal: the default
           let "dec = 32"
           echo "decimal number = $dec"             # 32
           # Nothing out of the ordinary here.

           # Octal: numbers preceded by '0' (zero)
           let "oct = 032"
           echo "octal number = $oct"               # 26
           # Expresses result in decimal.
           # --------- ------ -- -------

           # Hexadecimal: numbers preceded by '0x' or '0X'
           let "hex = 0x32"
           echo "hexadecimal number = $hex"         # 50
           echo $((0x9abc))                         # 39612
           #     ^^      ^^   double-parentheses arithmetic expansion/evaluation
           # Expresses result in decimal.

           # Other bases: BASE#NUMBER
           # BASE between 2 and 64.
           # NUMBER must use symbols within the BASE range, see below.
           let "bin = 2#111100111001101"
           echo "binary number = $bin"              # 31181
           let "b32 = 32#77"
           echo "base-32 number = $b32"             # 231
           let "b64 = 64#@_"
           echo "base-64 number = $b64"             # 4031
           # This notation only works for a limited range (2 - 64) of ASCII characters.
           # 10 digits + 26 lowercase characters + 26 uppercase characters + @ + _
           echo
           echo $((36#zz)) $((2#10101010)) $((16#AF16)) $((53#1aA))
                                                    # 1295 170 44822 3375
           #  Important note:
           #  --------------
           #  Using a digit out of range of the specified base notation
           #+ gives an error message.
           let "bad_oct = 081"
           # (Partial) error message output:
           #  bad_oct = 081: value too great for base (error token is "081")
           #              Octal numbers use only digits in the range 0 - 7.
           exit $?   # Exit value = 1 (error)
                    
    •  Operator Precedence
           Operator                  Meaning                               Comments
                                                                           HIGHEST PRECEDENCE
           var++ var--               post-increment, post-decrement        C-style operators
           ++var --var               pre-increment, pre-decrement
           ! ~                       negation                              logical / bitwise, inverts sense of following operator
           **                        exponentiation                        arithmetic operation
           * / %                     multiplication, division, modulo      arithmetic operation
           + -                       addition, subtraction                 arithmetic operation
           << >>                     left, right shift                     bitwise
           -z -n                     unary comparison                      string is/is-not null
           -e -f -t -x, etc.         unary comparison                      file-test
           < -lt > -gt <= -le >= -ge compound comparison                   string and integer
           -nt -ot -ef               compound comparison                   file-test
           == -eq != -ne             equality / inequality                 test operators, string and integer
           &                         AND                                   bitwise
           ^                         XOR                                   exclusive OR, bitwise
           |                         OR                                    bitwise
           && -a                     AND                                   logical, compound comparison
           || -o                     OR                                    logical, compound comparison
           ?:                        trinary operator                      C-style
           =                         assignment                            (do not confuse with equality test)
           *= /= %= += -= <<= >>= &= combination assignment                times-equal, divide-equal, mod-equal, etc.
           ,                         comma                                 links a sequence of operations
                                                                           LOWEST PRECEDENC
Chapter 10. Manipulating Variables                             
     •  String Length:
         ${#string}
         expr length $string
            These are the equivalent of strlen() in C.
         expr "$string" : '.*'
         EX:stringZ=abcABC123ABCabc
            echo ${#stringZ}                 # 15
            echo `expr length $stringZ`      # 15
            echo `expr "$stringZ" : '.*'`    # 15
     • Length of Matching Substring at Beginning of String:
        expr match "$string" '$substring'
            $substring is a regular expression.
        expr "$string" : '$substring'
            $substring is a regular expression.
            EX: stringZ=abcABC123ABCabc
                #       |------|
                #       12345678
                echo `expr match "$stringZ" 'abc[A-Z]*.2'`   # 8
                echo `expr "$stringZ" : 'abc[A-Z]*.2'`       # 8
     • Index:
        expr index $string $substring
            Numerical position in $string of first character in $substring that matches.
            EX:stringZ=abcABC123ABCabc
               #       123456 ...
               echo `expr index "$stringZ" C12`             # 6
                                                            # C position.
               echo `expr index "$stringZ" 1c`              # 3
               # 'c' (in #3 position) matches before '1'.
               This is the near equivalent of strchr() in C.
     • Substring Extraction
        ${string:position}
            Extracts substring from $string at $position.
            If the $string parameter is "*" or "@", then this extracts the positional parameters, [48] starting at $position.
        ${string:position:length}
            Extracts $length characters of substring from $string at $position.
            stringZ=abcABC123ABCabc
            #       0123456789.....
            #       0-based indexing.
            echo ${stringZ:0}                            # abcABC123ABCabc
            echo ${stringZ:1}                            # bcABC123ABCabc
            echo ${stringZ:7}                            # 23ABCabc
            echo ${stringZ:7:3}                          # 23A
            echo ${stringZ:-4}                           # abcABC123ABCabc
            # Defaults to full string, as in ${parameter:-default}.
            # However . . .
            echo ${stringZ:(-4)}                         # Cabc
            echo ${stringZ: -4}                          # Cabc
            # Now, it works.
            # Parentheses or added space "escape" the position parameter.
            If the $string parameter is "*" or "@", then this extracts a maximum of $length positional
            parameters, starting at $position.
            echo ${*:2}          # Echoes second and following positional parameters.
            echo ${@:2}          # Same as above.
            echo ${*:2:3}        # Echoes three positional parameters, starting at second.
                                                         # Three characters of substring.
         expr substr $string $position $length
            Extracts $length characters from $string starting at $position.
            stringZ=abcABC123ABCabc
            #       123456789......
            #       1-based indexing.
            echo `expr substr $stringZ 1 2`              # ab
            echo `expr substr $stringZ 4 3`              # ABC
         expr match "$string" '\($substring\)'
            Extracts $substring at beginning of $string, where $substring is a regular expression.
         expr "$string" : '\($substring\)'
            Extracts $substring at beginning of $string, where $substring is a regular expression.
            stringZ=abcABC123ABCabc
            #       =======    
            echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'`   # abcABC1
            echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'`       # abcABC1
            echo `expr "$stringZ" : '\(.......\)'`                   # abcABC1
            # All of the above forms give an identical result.
         expr match "$string" '.*\($substring\)'
            Extracts $substring at end of $string, where $substring is a regular expression.
         expr "$string" : '.*\($substring\)'
            Extracts $substring at end of $string, where $substring is a regular expression.
            stringZ=abcABC123ABCabc
            #                ======
            echo `expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)'`    # ABCabc
            echo `expr "$stringZ" : '.*\(......\)'`                       # ABCabc
     •  Substring Removal:
         ${string#substring}
            Deletes shortest match of $substring from front of $string.
         ${string##substring}
            Deletes longest match of $substring from front of $string.
            stringZ=abcABC123ABCabc
            #       |----|          shortest
            #       |----------|    longest
            echo ${stringZ#a*C}      # 123ABCabc
            # Strip out shortest match between 'a' and 'C'.
            echo ${stringZ##a*C}     # abc
            # Strip out longest match between 'a' and 'C'.
            # You can parameterize the substrings.
            X='a*C'
            echo ${stringZ#$X}      # 123ABCabc
            echo ${stringZ##$X}     # abc
                                   # As above.
         ${string%substring}
            Deletes shortest match of $substring from back of $string.
            For example:
            # Rename all filenames in $PWD with "TXT" suffix to a "txt" suffix.
            # For example, "file1.TXT" becomes "file1.txt" . . .
            SUFF=TXT
            suff=txt
            for i in $(ls *.$SUFF)
            do
              mv -f $i ${i%.$SUFF}.$suff
              #  Leave unchanged everything *except* the shortest pattern match
              #+ starting from the right-hand-side of the variable $i . . .
            done ### This could be condensed into a "one-liner" if desired.
         ${string%%substring}
            Deletes longest match of $substring from back of $string.
            stringZ=abcABC123ABCabc
            #                    ||     shortest
            #        |------------|     longest
            echo ${stringZ%b*c}      # abcABC123ABCa
            # Strip out shortest match between 'b' and 'c', from back of $stringZ.
            echo ${stringZ%%b*c}     # a
            # Strip out longest match between 'b' and 'c', from back of $stringZ.
            This operator is useful for generating filenames.
     •  Substring Replacement
         ${string/substring/replacement}
            Replace first match of $substring with $replacement.
         ${string//substring/replacement}
            Replace all matches of $substring with $replacement.
            stringZ=abcABC123ABCabc
            echo ${stringZ/abc/xyz}       # xyzABC123ABCabc
                                          # Replaces first match of 'abc' with 'xyz'.
            echo ${stringZ//abc/xyz}      # xyzABC123ABCxyz
                                          # Replaces all matches of 'abc' with # 'xyz'.
            echo  ---------------
            echo "$stringZ"               # abcABC123ABCabc
            echo  ---------------
                                          # The string itself is not altered!
            # Can the match and replacement strings be parameterized?
            match=abc
            repl=000
            echo ${stringZ/$match/$repl}  # 000ABC123ABCabc
            #              ^      ^         ^^^
            echo ${stringZ//$match/$repl} # 000ABC123ABC000
            # Yes!          ^      ^        ^^^         ^^^
            echo
            # What happens if no $replacement string is supplied?
            echo ${stringZ/abc}           # ABC123ABCabc
            echo ${stringZ//abc}          # ABC123ABC
            # A simple deletion takes place.
         ${string/#substring/replacement}
            If $substring matches front end of $string, substitute $replacement for $substring.
         ${string/%substring/replacement}
            If $substring matches back end of $string, substitute $replacement for $substring.
            stringZ=abcABC123ABCabc
            echo ${stringZ/#abc/XYZ}          # XYZABC123ABCabc
                                              # Replaces front-end match of 'abc' with 'XYZ'.
            echo ${stringZ/%abc/XYZ}          # abcABC123ABCXYZ
                                           # Replaces back-end match of 'abc' with 'XYZ'.
      • Parameter Substitution:
      • Manipulating and/or expanding variables 
         ${parameter}   May be used for concatenating variables with strings.
             your_id=${USER}-on-${HOSTNAME}
             echo "$your_id"
             #
             echo "Old \$PATH = $PATH"
             PATH=${PATH}:/opt/bin  # Add /opt/bin to $PATH for duration of script.
             echo "New \$PATH = $PATH"
         ${parameter-default}, ${parameter:-default}
             If parameter not set, use default.
             var1=1
             var2=2
             # var3 is unset.
             echo ${var1-$var2}   # 1
             echo ${var3-$var2}   # 2
             #           ^          Note the $ prefix.
             echo ${username-`whoami`}
             # Echoes the result of `whoami`, if variable $username is still unset.
             ${parameter-default} and ${parameter:-default} are almost equivalent.
             The extra : makes a difference only when parameter has been declared, but is null.
             variable=
             # variable has been declared, but is set to null.
             echo "${variable-0}"    # (no output)
             echo "${variable:-1}"   # 1
             #               ^
             unset variable
             echo "${variable-2}"    # 2
             echo "${variable:-3}"   # 3
         ${parameter=default}, ${parameter:=default}
             If parameter not set, set it to default.
             Both forms nearly equivalent. The : makes a difference only when $parameter has been declared and is null.
             echo ${var=abc}   # abc
             echo ${var=xyz}   # abc
             # $var had already been set to abc, so it did not change.
         ${parameter+alt_value}, ${parameter:+alt_value}
             If parameter set, use alt_value, else use null string.
             Both forms nearly equivalent. The : makes a difference only when parameter has been declared and is null.
             echo "###### \${parameter+alt_value} ########"
             a=${param1+xyz}
             echo "a = $a"      # a =
             param2=
             a=${param2+xyz}
             echo "a = $a"      # a = xyz
             param3=123
             a=${param3+xyz}
             echo "a = $a"      # a = xyz
             echo
             echo "###### \${parameter:+alt_value} ########"
             echo
             a=${param4:+xyz}
             echo "a = $a"      # a =
             param5=
             a=${param5:+xyz}
             echo "a = $a"      # a =
             # Different result from   a=${param5+xyz}
             param6=123
             a=${param6:+xyz}
             echo "a = $a"      # a = xyz
          ${parameter?err_msg}, ${parameter:?err_msg}
             If parameter set, use it, else print err_msg and abort the script with an exit status of 1.
             Both forms nearly equivalent. The : makes a difference only when parameter has been declared and is null, as above.
             #  Check some of the system's environmental variables.
             #  This is good preventative maintenance.
             #  If, for example, $USER, the name of the person at the console, is not set,
             #+ the machine will not recognize you.
             : ${HOSTNAME?} ${USER?} ${HOME?} ${MAIL?}
               echo
               echo "Name of the machine is $HOSTNAME."
               echo "You are $USER."
               echo "Your home directory is $HOME."
               echo "Your mail INBOX is located in $MAIL."
               echo
               echo "If you are reading this message,"
               echo "critical environmental variables have been set."
               echo
               echo
             # ------------------------------------------------------
       • Variable length / Substring removal
          ${#var} String length (number of characters in $var). For an array, ${#array} is the length of the first element in the array.
             Exceptions:
          ${#*} and ${#@} give the number of positional parameters.
             For an array, ${#array[*]} and ${#array[@]} give the number of elements in the array.
          ${var#Pattern}, ${var##Pattern}
             ${var#Pattern} Remove from $var the shortest part of $Pattern that matches the front end of $var.
             ${var##Pattern} Remove from $var the longest part of $Pattern that matches the front end of $var.
          ${var%Pattern}, ${var%%Pattern}
             ${var%Pattern} Remove from $var the shortest part of $Pattern that matches the back end of $var.
             ${var%%Pattern} Remove from $var the longest part of $Pattern that matches the back end of $var.
       • Variable expansion / Substring replacement
          These constructs have been adopted from ksh.
          ${var:pos}
             Variable var expanded, starting from offset pos.
          ${var:pos:len}
             Expansion to a max of len characters of variable var, from offset pos. See Example A-13 for an
             example of the creative use of this operator.
          ${var/Pattern/Replacement} First match of Pattern, within var replaced with Replacement.
             If Replacement is omitted, then the first match of Pattern is replaced by nothing, that is, deleted.
          ${var//Pattern/Replacement}
             Global replacement.  All matches of Pattern, within var replaced with Replacement.
             As above, if Replacement is omitted, then all occurrences of Pattern are replaced by nothing, that is, deleted.
          ${var/#Pattern/Replacement}
             If prefix of var matches Pattern, then substitute Replacement for Pattern.
          ${var/%Pattern/Replacement}
             If suffix of var matches Pattern, then substitute Replacement for Pattern.
          ${!varprefix*}, ${!varprefix@}
             Matches names of all previously declared variables beginning with varprefix.
             # This is a variation on indirect reference, but with a * or @.
             # Bash, version 2.04, adds this feature.
             xyz23=whatever
             xyz24=
             a=${!xyz*}         #  Expands to *names* of declared variables
             # ^ ^   ^           + beginning with "xyz".
             echo "a = $a"      #  a = xyz23 xyz24
             a=${!xyz@}         #  Same as above.
             echo "a = $a"      #  a = xyz23 xyz24
             echo "---"
             abc23=something_else
             b=${!abc*}
             echo "b = $b"      #  b = abc23
             c=${!b}            #  Now, the more familiar type of indirect reference.
             echo $c            #  something_else

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