it with a closing parenthesis. For example, MYDATE=$(date)
assigns the output from the date
command to the MYDATE
variable. Enclosing the command in back-ticks (`)
can have the same effect. In this case, the date
command is run when the variable is set and not each time the variable is read.
Escaping Special Shell Characters
Keep in mind that characters such as the dollar sign ($
), back-tick (`
), asterisk (*
), exclamation point (!
), and others have special meaning to the shell, which you will see as you proceed through this chapter. On some occasions, you want the shell to use these characters’ special meaning and other times you don't. For example, if you typed echo $HOME
, the shell would think that you meant to display the name of your home directory (stored in the $HOME
variable) to the screen (such as /home/chris
) because a $
indicates a variable name follows that character.
If you wanted literally to show $HOME
, you would need to escape the $
. Typing echo
'$HOME' or echo \$HOME
would literally show $HOME
on the screen. So, if you want to have the shell interpret a single character literally, precede it with a backslash (\
). To have a whole set of characters interpreted literally, surround those characters with single quotes ('
).
Using double quotes is a bit trickier. Surround a set of text with double quotes if you want all but a few characters used literally. For example, with text surrounded with double quotes, dollar signs ($
), back-ticks (`
), and exclamation points (!
) are interpreted specially, but other characters (such as an asterisk) are not. Type these three lines to see the different output (shown on the right):
echo '$HOME * `date`' $HOME * `date` echo ″$HOME * `date`″ /home/chris * Tue Jan 21 16:56:52 EDT 2020 echo $HOME * `date` /home/chris file1 file2 Tue Jan 21 16:56:52 EDT 2020
Using variables is a great way to get information that can change from computer to computer or from day to day. The following example sets the output of the uname -n
command to the MACHINE
variable. Then I use parentheses to set NUM_FILES
to the number of files in the current directory by piping (|
) the output of the ls
command to the word count command (wc -l
):
MACHINE=`uname -n` NUM_FILES=$(/bin/ls | wc -l)
Variables can also contain the value of other variables. This is useful when you have to preserve a value that will change so that you can use it later in the script. Here, BALANCE
is set to the value of the CurBalance
variable:
BALANCE="$CurBalance"
NOTE
When assigning variables, use only the variable name (for example, BALANCE
). When you reference a variable, meaning that you want the value of the variable, precede it with a dollar sign (as in $CurBalance
). The result of the latter is that you get the value of the variable, not the variable name itself.
Special shell positional parameters
There are special variables that the shell assigns for you. One set of commonly used variables is called positional parameters or command-line arguments, and it is referenced as $0, $1, $2, $3…$n. $0 is special, and it is assigned the name used to invoke your script; the others are assigned the values of the parameters passed on the command line in the order they appeared. For instance, let's say that you had a shell script named myscript
which contained the following:
#!/bin/bash # Script to echo out command-line arguments echo "The first argument is $1, the second is $2." echo "The command itself is called $0." echo "There are $# parameters on your command line" echo "Here are all the arguments: $@"
Assuming that the script is executable and located in a directory in your $PATH
, the following shows what would happen if you ran that command with foo
and bar
as arguments:
$ chmod 755 /home/chris/bin/myscript $ myscript foo bar The first argument is foo, the second is bar. The command itself is called /home/chris/bin/myscript. There are 2 parameters on your command line Here are all the arguments: foo bar
As you can see, the positional parameter $0
is the full path or relative path to myscript
, $1
is foo
, and $2
is bar
.
Another variable, $#
, tells you how many parameters your script was given. In the example, $#
would be 2. The $@
variable holds all of the arguments entered at the command line. Another particularly useful special shell variable is $?
, which receives the exit status of the last command executed. Typically, a value of zero means that the command exited successfully, and anything other than zero indicates an error of some kind. For a complete list of special shell variables, refer to the bash
man page.
Reading in parameters
Using the read
command, you can prompt the user for information and store that information to use later in your script. Here's an example of a script that uses the read
command:
#!/bin/bash read -p "Type in an adjective, noun and verb (past tense): " adj1 noun1 verb1 echo "He sighed and $verb1 to the elixir. Then he ate the $adj1 $noun1."
In this script, after the script prompts for an adjective, noun, and verb, the user is expected to enter words that are then assigned to the adj1
, noun1
, and verb1
variables. Those three variables are then included in a silly sentence, which is displayed on the screen. If the script were called sillyscript
, here's an example of how it might run:
$ chmod 755 /home/chris/bin/sillyscript $ sillyscript Type in an adjective, noun and verb (past tense): hairy football danced He sighed and danced to the elixir. Then he ate the hairy football.
Parameter expansion in bash
As mentioned earlier, if you want the value of a variable, you precede it with a $
(for example, $CITY
). This is really just shorthand for the notation ${CITY}
; curly braces are used when the value of the parameter needs to be placed next to other text without a space. Bash has special rules that allow you to expand the value of a variable in different ways. Going into all of the rules is probably overkill for a quick introduction to shell scripts, but the following list presents some common constructs you're likely to see in bash scripts that you find on your Linux system.
${var:-value}: If variable is unset or empty, expand this to value.
${var#pattern}: Chop the shortest match for pattern from the front of var's value.
${var##pattern}: Chop the longest match for pattern from the front of var's value.
${var%pattern}: Chop the shortest match for pattern from the end of var's value.
${var%%pattern}: Chop the longest match for pattern from the end of var's value.
Try typing the following commands from a shell to test how parameter expansion works:
$ THIS="Example" $ THIS=${THIS:-"Not Set"} $ THAT=${THAT:-"Not Set"} $ echo $THIS Example $ echo $THAT Not Set
In the examples here, the THIS
variable is initially set to the word Example
. In the next two lines, the THIS
and THAT
variables are set to their current values or to Not Set
, if they are not currently set. Notice that because