Extract from:
http://wiki.bash-hackers.org/syntax/pe Bash Parameter expansionIndirection
In some cases, like for example ${PARAMETER} ${PARAMETER:0:3} you can instead use the form ${!PARAMETER}
to enter a level of indirection. The referenced parameter is not
read -rep 'Which variable do you want to inspect? ' look_var printf 'The value of "%s" is: "%s"\n' "$look_var" "${!look_var}" Of course the indirection also works with special variables: # set some fake positional parameters set one two three four # get the LAST argument ("#" stores the number of arguments, so "!#" will reference the LAST argument) echo ${!#}
You can think of this mechanism as being roughly equivalent to
taking any parameter expansion that begins with the parameter
name, and substituting the echo "${!var^^}" # ...is equivalent to eval 'echo "${'"$var"'^^}"'
It was an unfortunate design decision to use the Indirect references to array names are also possible since the Bash 3 series (exact version unknown), but undocumented. See indirection for details. Chet has added an initial implementation of
the ksh Case modification
These expansion operators modify the case of the letters in the expanded text. The The (currently undocumented)
operators Example: Rename all for file in *.txt; do mv "$file" "${file,,}" done
Note: The feature worked word-wise in Bash 4 RC1
(a modification of a parameter containing Case modification: ArraysFor array
expansion, the case modification applies to every
expanded element, no matter if you expand an individual index or
mass-expand the whole array using Assume:
⇒
⇒
⇒
⇒
⇒ Variable name expansion
This expands to a list of all set variable
names beginning with the string This will show all defined variable names (not values!) beginning with "BASH": $ echo ${!BASH*} BASH BASH_ARGC BASH_ARGV BASH_COMMAND BASH_LINENO BASH_SOURCE BASH_SUBSHELL BASH_VERSINFO BASH_VERSION This list will also include array names. Substring removal
This one can expand only a part of a parameter's value, given a pattern to describe what to remove from the string. The pattern is interpreted just like a pattern to describe a filename to match (globbing). See Pattern matching for more. Example string (just a quote from a big man): MYSTRING="Be liberal in what you accept, and conservative in what you send" From the beginning
This form is to remove the described pattern
trying to match it from the beginning of the string.
The operator "
From the end
In the second form everything will be the same, except that Bash now tries to match the pattern from the end of the string:
Common useHow the heck does that help to make my life easier? Well, maybe the most common use for it is to extract parts of a filename. Just look at the following list with examples: Get name without extension
⇒
Get extension
⇒
bash_hackers. Get directory name
⇒
Get filename
⇒ /home/bash/ These are the syntaxes for filenames with a single extension. Depending on your needs, you might need to adjust shortest/longest match. Substring removal: ArraysAs for most parameter expansion features, working on arrays will handle each expanded element, for individual expansion and also for mass expansion. Simple example, removing a trailing Assume:
⇒ (it was: All other variants of this expansion behave the same. Search and replace
This one can substitute (replace) a substring matched by a pattern, on expansion time. The matched substring will be entirely removed and the given string will be inserted. Again some example string for the tests: MYSTRING="Be liberal in what you accept, and conservative in what you send"
The two main forms only differ in the number of slashes
after the parameter name: The first one (one slash) is to only substitute the first occurrence of the given pattern, the second one (two slashes) is to substitute all occurrences of the pattern. First, let's try to say "happy" instead of "conservative" in our example string: ${MYSTRING//conservative/happy}
⇒ Since there is only one "conservative" in that example, it really doesn't matter which of the two forms we use. Let's play with the word "in", I don't know if it makes any sense, but let's substitute it with "by". First form: Substitute first occurrence ${MYSTRING/in/by}
⇒ Second form: Substitute all occurrences ${MYSTRING//in/by}
⇒ Anchoring Additionally you
can "anchor" an expression: A MYSTRING=xxxxxxxxxx echo ${MYSTRING/#x/y} # RESULT: yxxxxxxxxx echo ${MYSTRING/%x/y} # RESULT: xxxxxxxxxy If the replacement part is completely omitted, the matches are replaced by the nullstring, i.e., they are removed. This is equivalent to specifying an empty replacement: echo ${MYSTRING//conservative/} # is equivalent to echo ${MYSTRING//conservative} Search and replace: ArraysThis parameter expansion type applied to arrays applies to all expanded elements, no matter if an individual element is expanded, or all elements using the mass expansion syntaxes. A simple example, changing the (lowercase)
letter Assume:
⇒
⇒ String length
When you use this form, the length of the parameter's value is expanded. Again, a quote from a big man, to have a test text: MYSTRING="Be liberal in what you accept, and conservative in what you send"
Using echo ⇒ The length is reported in characters, not in bytes. Depending on your environment this may not always be the same (multibyte-characters, like in UTF8 encoding). There's not much to say about it, mh? (String) length: ArraysFor arrays, this expansion type has two meanings: For individual elements, it reports the string length of the element (as for every "normal" parameter) For the mass subscripts
Example: Assume:
⇒ 2 (the word "is" has a length of 2)
⇒ 4 (the array contains 4 elements) Attention: The number of used elements does not need to conform to the highest index. Sparse arrays are possible in Bash, that means you can have 4 elements, but with indexes 1, 7, 20, 31. You can't loop through such an array with a counter loop based on the number of elements! Substring expansion
This one can expand only a part
of a parameter's value, given a position to start
and maybe a length. If
Example string (a quote from a big man):
Using only OffsetIn the first form, the expansion is used without a length value, note that the offset 0 is the first character: echo ${MYSTRING:34}
⇒ Be liberal in what you accept, and Using Offset and LengthIn the second form we also give a length value: echo ${MYSTRING:34:13}
⇒ Be liberal in what you accept, and Negative Offset ValueIf the given offset is negative, it's counted from the end of the string, i.e. an offset of -1 is the last character. In that case, the length still counts forward, of course. One special thing is to do when using a negative offset: You need to separate the (negative) number from the colon: ${MYSTRING: -10:5} ${MYSTRING:(-10):5} Why? Because it's interpreted as the parameter expansion syntax to use a default value. Negative Length ValueIf the echo "${MYSTRING:11:-17}"
⇒ Be liberal This works since Bash 4.2-alpha, see also Bash changes. Substring/Element expansion: ArraysFor arrays, this expansion type has again 2 meanings: For individual elements, it expands to the specified substring (as for every “normal” parameter) For the mass subscripts
Example: Assume:
⇒
⇒ Use a default value
If the parameter echo "Your home directory is: ${HOME:-/home/$USER}." echo "${HOME:-/home/$USER} will be used to store your personal data."
If #!/bin/bash read -p "Enter your gender (just press ENTER to not tell us): " GENDER echo "Your gender is ${GENDER:-a secret}." It will print "Your gender is a secret." when you don't enter the gender. Note that the default value is used on expansion time, it is not assigned to the parameter. Use a default value: ArraysFor arrays,
the behaviour is very similar. Again, you have to make a
difference between expanding an individual element by a given
index and mass-expanding the array using the For
individual elements, it's the very same: If the expanded element
is For mass-expansion syntax, the default text is expanded if the array contains no
element or is unset (the contains only elements that are the
nullstring (the In other words: The basic meaning of this expansion type is applied as consistent as possible to arrays. Example code (please try the example cases yourself): #### # Example cases for unset/empty arrays and nullstring elements #### ### CASE 1: Unset array (no array) # make sure we have no array at all unset array echo ${array[@]:-This array is NULL or unset} echo ${array[@]-This array is NULL or unset} ### CASE 2: Set but empty array (no elements) # declare an empty array array=() echo ${array[@]:-This array is NULL or unset} echo ${array[@]-This array is NULL or unset} ### CASE 3: An array with only one element, a nullstring array=("") echo ${array[@]:-This array is NULL or unset} echo ${array[@]-This array is NULL or unset} ### CASE 4: An array with only two elements, a nullstring and a normal word array=("" word) echo ${array[@]:-This array is NULL or unset} echo ${array[@]-This array is NULL or unset} Assign a default value
This one works like the using
default values, but the default text you give is
not only expanded, but also assigned to the
parameter, if it was unset or null. Equivalent to using a default
value, when you omit the echo "Your home directory is: ${HOME:=/home/$USER}." echo "$HOME will be used to store your personal data."
After the first expansion here ( Let's change our code example from above: #!/bin/bash read -p "Enter your gender (just press ENTER to not tell us): " GENDER echo "Your gender is ${GENDER:=a secret}." echo "Ah, in case you forgot, your gender is really: $GENDER" Assign a default value: ArraysFor arrays
this expansion type is limited. For an individual index, it
behaves like for a "normal" parameter, the default
value is assigned to this one element. The mass-expansion
subscripts Use an alternate value
This form expands to nothing if the parameter is unset or empty. If it is set, it does not expand to the parameter's value, but to some text you can specify: echo "The Java application was installed and can be started.${JAVAPATH:+ NOTE: JAVAPATH seems to be set}"
The above code will simply add a warning if Some more unrealistic example… Ask for some flags (for whatever reason), and then, if they were set, print a warning and also print the flags: #!/bin/bash read -p "If you want to use special flags, enter them now: " SPECIAL_FLAGS echo "The installation of the application is finished${SPECIAL_FLAGS:+ (NOTE: there are special flags set: $SPECIAL_FLAGS)}."
If you omit the colon, as shown in the second form
( # test that with the three stages: # unset foo # foo="" # foo="something" if [[ ${foo+isset} = isset ]]; then echo "foo is set..." else echo "foo is not set..." fi Use an alternate value: ArraysSimilar to the cases for arrays
to expand to a default value, this expansion behaves like for a
"normal" parameter when using individual array elements
by index, but reacts differently when using the mass-expansion
subscripts For individual elements, it's the very same: If the expanded element is not NULL or unset (watch the :+ and + variants), the alternate text is expanded For mass-expansion syntax, the alternate text is expanded if the array contains elements where min. one element is not a nullstring (the :+ and + variants mean the same here) contains only elements that are not the nullstring (the :+ variant) For some cases to play with, please see the code examples in the description for using a default value. Display error if null or unset
If the parameter $ echo "The unset parameter is: ${p_unset?not set}" bash: p_unset: not set After printing this message, an
interactive shell has a non-interactive shell exits with a non-zero exit code The meaning of the colon ( only unset or unset and empty parameters are taken into account.
|