Have you ever wanted to change the names of many files at once? How about using a default value for a variable if it has no value? These and many other options are available to you through string operators in bash and other Bourne shell derived shells.
String operators allow you to manipulate the contents of a variable
without having to write your own shell functions to do so. They are
provided through 'curly brace' syntax. Any variable can be displayed
like this ${foo}
without changing its meaning. This
functionality is often used to protect a variable name from
surrounding characters.
bash-2.02$ export foo=foo
bash-2.02$ echo ${foo}bar # foo exists so this works
foobar
bash-2.02$ echo $foobar # foobar doesn't exist, so this fails
bash-2.02$
By the end of this article, you'll be able to use it for a whole lot more.
There are three kinds of variable substitution:
There are two kinds of pattern matching available, matching from the left and matching from the right. The operators, with their functions and an expample, are shown in the following table:
Operator | Function | Example |
---|---|---|
${foo#t*is} |
deletes the shortest possible match from the left |
export $foo="this is a test"
|
${foo##t*is} |
deletes the longest possible match from the left |
export $foo="this is a test"
|
${foo%t*st} |
deletes the shortest possible match from the right |
export $foo="this is a test"
|
${foo%%t*st} |
deletes the longest possible match from the right |
export $foo="this is a test"
|
Note: While the
#
and%
identifiers may not seem obvious, they have a convenient mnemonic. The#
key is on the left side of the$
key and operates from the left. The%
key is on the right of the$
key and operated from the right.
These operators can be used to do a variety of things. For example, the following script will change the extension of all '.html' files to '.htm'.
#!/bin/bash
# quickly convert html filenames for use on a dossy system
# only handles file extensions, not file names
for i in *.html; do
if [ -f ${i%l} ]; then
echo ${i%l} already exists
else
mv $i ${i%l}
fi
done
Another kind of variable mangling you might want to employ is substitution. There are four substitution operators in Bash. They are shown in the following table:
Operator | Function | Example |
---|---|---|
${foo:-bar} |
If $foo exists and is not null, return $foo. If it doesn't exist, or is null, return bar. |
export foo=""
|
${foo:=bar} |
If $foo exists and is not null, return $foo. If it doesn't exist, or is null, set $foo to bar and return bar |
export foo=""
|
${foo:+bar} |
If $foo exists and is not null, return bar. If it doesn't exist, or is null, return a null. |
export foo="this is a test"
|
${foo:?"error message"} |
If $foo exists and isn't null, return it's value. If it doesn't
exist, or is null, print the error message. If no error message is
given, it prints parameter null or not
set .Note: In a non-interactive shell, this will abort the current script. In an interactive shell, this will just print the error message. |
export foo="one"
|
Note: The:
in the above operators can be omitted. Doing so changes the behavior of the operator to only test for existence of the variable. This will cause the creation of a variable in the case of${foo=bar}
These operators can be used in a variety of ways. A good example would be to give a default value to a variable normally read from the command line arguments when no arguments are given. This is shown in the following script.
#!/bin/bash
export INFILE=${1-"infile"}
export OUTFILE=${2-"outfile"}
cat $INFILE > $OUTFILE
Hopefully this gives you something to think about and to play with until the next article. If you're interested in more hints about bash (or other stuff I've written about), please take a look at my home page. If you've got questions or comments, please drop me a line.