Extract from: http://wiki.bash-hackers.org/syntax/pe Date: 2017-08-06 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: Arrays
For 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:
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:
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}⇒ Be liberal in what you accept, and
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}⇒ Be liberal
Second form: Substitute all occurrences ${MYSTRING//in/by}⇒ Be liberal
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:
Example:
Assume:
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}⇒
Using Offset and LengthIn the second form we also give a length value: echo ${MYSTRING:34:13}⇒
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 Value
If the echo "${MYSTRING:11:-17}"⇒
This works since Bash 4.2-alpha, see also Bash changes. Substring/Element expansion: ArraysFor arrays, this expansion type has again 2 meanings:
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: Arrays
For 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
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: Arrays
For 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 JAVAPATH is set (because it could influence the startup behaviour of that imaginary application).
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: Arrays
Similar 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 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,
The meaning of the colon (
are taken into account. |