I'd recommend reading the
Shell Expansions section in the
Bash Reference Manual instead.
Here is a trivial example on
substitution:
I needed a script that searches files in the directories I specify, or all filesystems (starting at root /) if I don't specify any directories.
Normally, if you don't give any paths to
find, it starts the search at the current directory.
You could use
Code:
#!/bin/bash
if [ $# -gt 0 ]; then
find "$@" -type f
else
find / -type f
fi
or similar if-then-else constructs, but you do not have to, since
Code:
#!/bin/bash
find "${@:-/}" -type f
does the exact same thing using substitution.
Here,
$@ is the special variable that expands to all parameters given on the command line, and
$# expands to the number of parameters specified on the command line. They work just like all other shell variables, they just have funny names.
${variable:-value} expands to the value of
variable, if the value is not empty. Otherwise it will expand to
value.
Other substitutions I've used often are
${variable##pattern}, where
pattern is a glob pattern (similar to file name patterns). The longest initial match (if any) is removed from the value of
variable. I also use
# for the shortest initial match,
% for the shortest final match, and
%% for the longest final match a lot.
Here's another real life example, this time a lot more complex:
For example, assume you have
Code:
pair="the name field = the value field"
which you wish to parse to a name and a value, converting all linear whitespace to single spaces, and trimming whitespace from both name and value. The usual answer is to use sed:
Code:
name="`echo "$pair" | sed -e 's|[\t\n\v\f\r ]\+| |g; s|^ *\([^=]*[^= ]\) *=.*$|\1|g'`"
value="`echo "$pair" | sed -e 's|[\t\n\v\f\r ]\+| |g; s|^[^=]*= *||'`"
but you can also do it directly in Bash, using variable substitutions:
Code:
LWS="`echo -ne '\t\n\v\f\r '`"
name="${pair//[$LWS]/ }" # Convert whitespaces to spaces
name="${name// / }" # Combine whitespaces
name="${name// / }" # Combine whitespaces
name="${name// / }" # Combine whitespaces
value="${name#*=}" # Copy pair with name removed to value
name="${name%%=*}" # Remove value part from name
value="${value# }" # Remove leading space from value
value="${value% }" # Remove trailing space from value
name="${name# }" # Remove leading space from name
name="${name% }" # Remove trailing space from value
I run a number of tests on my x86-64 machine (doing the above conversions in a Bash loop). The sed method takes about 7.5ms per pair, but the substitution method takes only about 0.6ms per pair. If you work with say a large configuration file, using substitutions instead of sed cuts the running time to one tenth!
Personally I also like how the parameter substitutions are easy to comment. (It is possible to comment sed patterns, too, but I find it messy.)