Advanced Bash-Scripting Guide: A complete guide to shell scripting | ||
---|---|---|
Prev | Chapter 9. Variables Revisited | Next |
Manipulating and/or expanding variables
Same as $parameter, i.e., value of the variable parameter. In certain contexts, only the less ambiguous ${parameter} form works.
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" |
If parameter not set, use default.
echo ${username-`whoami`} # Echoes the result of `whoami`, if variable $username is still unset. |
This is almost equivalent to ${parameter:-default}. The extra : makes a difference only when parameter has been declared, but is null. |
#!/bin/bash username0= # username0 has been declared, but is set to null. echo "username0 = ${username0-`whoami`}" # Will not echo. echo "username1 = ${username1-`whoami`}" # username1 has not been declared. # Will echo. username2= # username2 has been declared, but is set to null. echo "username2 = ${username2:-`whoami`}" # Will echo because of :- rather than just - in condition test. exit 0 |
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, [1] as above.
echo ${username=`whoami`} # Variable "username" is now set to `whoami`. |
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, see below.
echo "###### \${parameter+alt_value} ########" echo 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 |
If parameter set, use it, else print err_msg.
Both forms nearly equivalent. The : makes a difference only when parameter has been declared and is null, as above.
Example 9-11. Using param substitution and :
#!/bin/bash # Check some of the system's environmental variables. # 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 # ------------------------------------------------------ # The ${variablename?} construction can also check #+ for variables set within the script. ThisVariable=Value-of-ThisVariable # Note, by the way, that string variables may be set #+ to characters disallowed in their names. : ${ThisVariable?} echo "Value of ThisVariable is $ThisVariable". echo echo : ${ZZXy23AB?"ZZXy23AB has not been set."} # If ZZXy23AB has not been set, #+ then the script terminates with an error message. # You can specify the error message. # : ${ZZXy23AB?"ZZXy23AB has not been set."} # Same result with: dummy_variable=${ZZXy23AB?} # dummy_variable=${ZZXy23AB?"ZXy23AB has not been set."} # # echo ${ZZXy23AB?} >/dev/null echo "You will not see this message, because script terminated above." HERE=0 exit $HERE # Will *not* exit here. |
Parameter substitution and/or expansion. The following expressions are the complement to the match in expr string operations (see Example 12-6). These particular ones are used mostly in parsing file path names.
Variable length / Substring removal
String length (number of characters in $var). For an array, ${#array} is the length of the first element in the array.
Exceptions:
|
Example 9-12. Length of a variable
#!/bin/bash # length.sh E_NO_ARGS=65 if [ $# -eq 0 ] # Must have command-line args to demo script. then echo "Invoke this script with one or more command-line arguments." exit $E_NO_ARGS fi var01=abcdEFGH28ij echo "var01 = ${var01}" echo "Length of var01 = ${#var01}" echo "Number of command-line arguments passed to script = ${#@}" echo "Number of command-line arguments passed to script = ${#*}" exit 0 |
Remove from $var the shortest/longest part of $pattern that matches the front end of $var.
A usage illustration from Example A-6:
# Function from "days-between.sh" example. # Strips leading zero(s) from argument passed. strip_leading_zero () # Better to strip possible leading zero(s) { # from day and/or month val=${1#0} # since otherwise Bash will interpret them return $val # as octal values (POSIX.2, sect 2.9.2.1). } |
Another usage illustration:
echo `basename $PWD` # Basename of current working directory. echo "${PWD##*/}" # Basename of current working directory. echo echo `basename $0` # Name of script. echo $0 # Name of script. echo "${0##*/}" # Name of script. echo filename=test.data echo "${filename##*.}" # data # Extension of filename. |
Remove from $var the shortest/longest part of $pattern that matches the back end of $var.
Version 2 of Bash adds additional options.
Example 9-13. Pattern matching in parameter substitution
#!/bin/bash # Pattern matching using the # ## % %% parameter substitution operators. var1=abcd12345abc6789 pattern1=a*c # * (wild card) matches everything between a - c. echo echo "var1 = $var1" # abcd12345abc6789 echo "var1 = ${var1}" # abcd12345abc6789 (alternate form) echo "Number of characters in ${var1} = ${#var1}" echo "pattern1 = $pattern1" # a*c (everything between 'a' and 'c') echo echo '${var1#$pattern1} =' "${var1#$pattern1}" # d12345abc6789 # Shortest possible match, strips out first 3 characters abcd12345abc6789 # ^^^^^ |-| echo '${var1##$pattern1} =' "${var1##$pattern1}" # 6789 # Longest possible match, strips out first 12 characters abcd12345abc6789 # ^^^^^ |----------| echo; echo pattern2=b*9 # everything between 'b' and '9' echo "var1 = $var1" # Still abcd12345abc6789 echo "pattern2 = $pattern2" echo echo '${var1%pattern2} =' "${var1%$pattern2}" # abcd12345a # Shortest possible match, strips out last 6 characters abcd12345abc6789 # ^^^^ |----| echo '${var1%%pattern2} =' "${var1%%$pattern2}" # a # Longest possible match, strips out last 12 characters abcd12345abc6789 # ^^^^ |-------------| # Remember, # and ## work from the left end of string, # % and %% work from the right end. echo exit 0 |
Example 9-14. Renaming file extensions:
#!/bin/bash # rfe # --- # Renaming file extensions. # # rfe old_extension new_extension # # Example: # To rename all *.gif files in working directory to *.jpg, # rfe gif jpg ARGS=2 E_BADARGS=65 if [ $# -ne $ARGS ] then echo "Usage: `basename $0` old_file_suffix new_file_suffix" exit $E_BADARGS fi for filename in *.$1 # Traverse list of files ending with 1st argument. do mv $filename ${filename%$1}$2 # Strip off part of filename matching 1st argument, # then append 2nd argument. done exit 0 |
Variable expansion / Substring replacement
These constructs have been adopted from ksh.
Variable var expanded, starting from offset pos.
Expansion to a max of len characters of variable var, from offset pos. See Example A-9 for an example of the creative use of this operator.
First match of patt, within var replaced with replacement.
If replacement is omitted, then the first match of patt is replaced by nothing, that is, deleted.
Global replacement. All matches of patt, within var replaced with replacement.
As above, if replacement is omitted, then all occurrences of patt are replaced by nothing, that is, deleted.
Example 9-15. Using pattern matching to parse arbitrary strings
#!/bin/bash var1=abcd-1234-defg echo "var1 = $var1" t=${var1#*-*} echo "var1 (with everything, up to and including first - stripped out) = $t" # t=${var1#*-} works just the same, #+ since # matches the shortest string, #+ and * matches everything preceding, including an empty string. # (Thanks, S. C. for pointing this out.) t=${var1##*-*} echo "If var1 contains a \"-\", returns empty string... var1 = $t" t=${var1%*-*} echo "var1 (with everything from the last - on stripped out) = $t" echo # ------------------------------------------- path_name=/home/bozo/ideas/thoughts.for.today # ------------------------------------------- echo "path_name = $path_name" t=${path_name##/*/} echo "path_name, stripped of prefixes = $t" # Same effect as t=`basename $path_name` in this particular case. # t=${path_name%/}; t=${t##*/} is a more general solution, #+ but still fails sometimes. # If $path_name ends with a newline, then `basename $path_name` will not work, #+ but the above expression will. # (Thanks, S.C.) t=${path_name%/*.*} # Same effect as t=`dirname $path_name` echo "path_name, stripped of suffixes = $t" # These will fail in some cases, such as "../", "/foo////", # "foo/", "/". # Removing suffixes, especially when the basename has no suffix, #+ but the dirname does, also complicates matters. # (Thanks, S.C.) echo t=${path_name:11} echo "$path_name, with first 11 chars stripped off = $t" t=${path_name:11:5} echo "$path_name, with first 11 chars stripped off, length 5 = $t" echo t=${path_name/bozo/clown} echo "$path_name with \"bozo\" replaced by \"clown\" = $t" t=${path_name/today/} echo "$path_name with \"today\" deleted = $t" t=${path_name//o/O} echo "$path_name with all o's capitalized = $t" t=${path_name//o/} echo "$path_name with all o's deleted = $t" exit 0 |
If prefix of var matches replacement, then substitute replacement for patt.
If suffix of var matches replacement, then substitute replacement for patt.
Example 9-16. Matching patterns at prefix or suffix of string
#!/bin/bash # Pattern replacement at prefix / suffix of string. v0=abc1234zip1234abc # Original variable. echo "v0 = $v0" # abc1234zip1234abc echo # Match at prefix (beginning) of string. v1=${v0/#abc/ABCDEF} # abc1234zip1234abc # |-| echo "v1 = $v1" # ABCDE1234zip1234abc # |---| # Match at suffix (end) of string. v2=${v0/%abc/ABCDEF} # abc1234zip123abc # |-| echo "v2 = $v2" # abc1234zip1234ABCDEF # |----| echo # ---------------------------------------------------- # Must match at beginning / end of string, #+ otherwise no replacement results. # ---------------------------------------------------- v3=${v0/#123/000} # Matches, but not at beginning. echo "v3 = $v3" # abc1234zip1234abc # NO REPLACEMENT. v4=${v0/%123/000} # Matches, but not at end. echo "v4 = $v4" # abc1234zip1234abc # NO REPLACEMENT. exit 0 |
Matches all previously declared variables beginning with varprefix.
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 # Bash, version 2.04, adds this feature. |
[1] |
If $parameter is null in a non-interactive script, it will terminate with a 127 exit status (the Bash error code code for "command not found"). |