6.3. VariablesBash allows creation and use of shell variables for the following purposes:
6.3.1. Creating/Assigning a Simple VariableTo assign a value to a simple variable, the syntax is similar to that of other shells (Figure 6-1).
If a variable doesn't exist, it is implicitly created; otherwise, its previous value is overwritten. A newly created variable is always local, although we may turn it into an environment variable using a method that I'll describe shortly. To assign a value that contains spaces, surround the value by quotes. Here are some examples: $ teamname="Denver Broncos" $ gameswon=12 $ gameslost=3 The set built-in command can be used to set and display shell settings and to display the value of shell variables (Figure 6-2).
The set built-in has many arguments and uses, which we'll discuss in several places in this chapter. Its simplest use is simply to display shell variables and their values: $ set gameslost=3 gameswon=12 teamname="Denver Broncos" $ _ Other output that set would produce has been omitted for clarity. The set built-in also has several other options, some of which we'll use later. Figure 6-3 is a list of the most useful options.
6.3.2. Accessing Simple VariablesFigure 6-4 lists the methods Bash supports for accessing the value of simple variables.
The following examples illustrate each access method. In the first example, I used braces to append a string to the value of a variable: $ verb=sing ...assign a variable. $ echo I like $verbing ...there's no variable "verbing". I like $ echo I like ${verb}ing ...now it works. I like singing $ _ Here's an example that uses command substitution to set the variable startDate to the current date if it's not already set: $ startDate=${startDate-'date'} ...if not set, run date. $ echo $startDate ...look at its value. In the next example, I set the variable x to a default value and printed its value, all at the same time: $ echo x = ${x=10} ...assign a default value. x = 10 $ echo $x ...confirm the variable was set. 10 $ _ In the following example, I displayed messages based on whether certain variables were set or not: $ flag=1 ...assign a variable. $ echo ${flag+'flag is set'} ...conditional message #1. flag is set $ echo ${flag2+'flag2 is set'} ...conditional message #2. ...result is null $ _ In the next example, I tried to access an undefined variable called grandTotal and received an error message instead: $ total=10 ...assign a variable. $ value=${total?'total not set'} ...accessed OK. $ echo $value ...look at its value. 10 $ value=${grandTotal?'grand total not set'} ...not set. grandTotal: grand total not set $ _ In this example, I ran a script that used the same access method as the previous example. Note that the script terminated when the access error occurred: $ cat script.sh ...look at the script. value=${grandTotal?'grand total is not set'} echo done # this line is never executed. $ script.sh ...run the script. script.sh: grandTotal: grand total is not set $ _ In this final example, I'll modify some variable values: $ echo $PWD ...display the current working directory. /home/glass/dir1 $ echo $HOME 6.3.3. Creating/Assigning a List VariableList variables, or arrays, are created with the declare built-in command (Figure 6-5), although simply using a variable in the form of an array will also work.
Here is an example of how you might create a list of teams: $ declare -a teamnames $ teamnames[0]="Dallas Cowboys" $ teamnames[1]="Washington Redskins" $ teamnames[2]="New York Giants" In reality, if you omit the declare command, the other lines will still work as expected. 6.3.4. Accessing List VariablesOnce you build a list of values, you will want to use them for something. When accessing array values, you can always put braces around the variable name to explicitly distinguish it from other text that might be around it (to prevent the shell from trying to use other text as part of the variable name (Figure 6-6).
The braces are required when using arrays to distinguish between other shell operators. Suppose, for example, we have our list of 32 NFL teams stored as $teamname[0] .. $teamname[31]. One might use this information this way: $ echo "There are ${#teamnames[*]} teams in the NFL" There are 32 teams in the NFL $ echo "They are: ${teamnames[*]}" ... 6.3.5. Building ListsYou can build an array or list variable in one of two ways. If you know how many elements you will need, you can use the declare built-in command to define the space and assign the values into specific locations in the list. If you don't know, or don't care, how many elements will be in the list, you can simply list them and they will be added in the order you specify. For example, to define our list of NFL teams, of which we know (at least today) there are 32, you might define it as follows: $ declare -a teamnames $ teamnames[0]="Dallas Cowboys" $ teamnames[1]="Washington Redskins" $ teamnames[2]="New York Giants" ... $ teamnames[31]="Houston Texans" This can also be done in a single (though long) command: $ declare -a teamnames $ teamnames=([0]="Dallas Cowboys" \ [1]="Washington Redskins" \ ... [31]="Houston Texans") The backslash is used to tell the shell that the command is continued on the next line. Even though we know the number of teams ahead of time, we don't need to know this to define the array. We could have also done it this way: $ teamnames = ("Dallas Cowboys" "Washington Redskins" \ "New York Giants" "New York Jets" \ ... "Houston Texans") Note that if you have sparsely populated the arraythat is, you have not assigned values in consecutive locations but skipped aroundwhen you ask for the number of values in the array, the value will be the actual number of populated elements, not the largest index defined. For example: $ mylist[0]=27 $ mylist[5]=30 $ echo ${#mylist[*]} ...number of elements in mylist[] 2 $ declare -a ...display defined element values declare -a mylist='([0]="27" [5]="30")' $ _ 6.3.6. Destroying listsList variables can be deallocated or destroyed using the unset built-in to Bash (Figure 6-7).
If you have finished using an array, you can deallocate the space used by the array by destroying it completely. It is more likely you will want to remove a specific element in the array. $ unset teamnames[17] Now our array contains 31 names instead of 32. 6.3.7. Reading a Variable from Standard InputThe read command allows you to read variables from standard input (Figure 6-8).
If you specify just one variable, the entire line is stored in the variable. Here's an example script that prompts a user for his or her full name: $ cat script.sh ...list the script. echo "Please enter your name: \c" read name # read just one variable. echo your name is $name # display the variable. $ bash script.sh ...run the script. Please enter your name: Graham Walker Glass your name is Graham Walker Glass ...whole line was read. $ _ Here's an example that illustrates what happens when you specify more than one variable: $ cat script.sh ...list the script. echo "Please enter your name: \c" read firstName lastName # read two variables. echo your first name is $firstName echo your last name is $lastName $ bash script.sh ...run the script. Please enter your name: Graham Walker Glass your first name is Graham ...first word. your last name is Walker Glass ...the rest. $ bash script.sh ...run it again. Please enter your name: Graham your first name is Graham ...first word. your last name is ...only one. $ _ 6.3.8. Exporting VariablesIn all shells, variables are local to the specific shell and, unless otherwise specified, are not passed to subshells. The export command allows you to mark local variables for export to the environment (Figure 6-9).
Although it's not necessary, I tend to use uppercase letters to name environment variables. The env utility allows you to modify and list environment variables (Figure 6-10).
In the following example, I created a local variable called DATABASE, which I then marked for export. When I created a subshell, a copy of the environment variable was inherited: $ export ...list my current exports. export TERM ...set in my ".profile" startup file. Bash provides a shell option that allows you to specify that, by default, all shell variables be exported to any subshells created. Shell options are defined with the set built-in (Figure 6-11).
6.3.9. Read-Only VariablesThe readonly command allows you to protect variables against modification (Figure 6-12).
In the following example, I protected a local variable from modification. I then exported the variable and showed that its copy did not inherit the read-only status: $ password=Shazam ...assign a local variable. $ echo $password ...display its value. Shazam 6.3.10. Predefined VariablesLike most shells, Bash defines some variables when it starts (Figure 6-13).
Here's a small shell script that illustrates the first three variables. In this example, the C compiler (gcc) was invoked on a file that didn't exist, and therefore returned a failure exit code. $ cat script.sh ...list the script. echo there are $# command line arguments: $@ gcc $1 # compile the first argument. echo the last exit value was $? # display exit code. $ script.sh nofile tmpfile ...execute the script. there are 2 command line arguments: nofile tmpfile gcc: nofile: No such file or directory gcc: no input files the last exit value was 1 ...gcc errored. $ _ The next example illustrates how $! may be used to kill the last background process: $ sleep 1000 & ...bg process, bash does not report PID. $ kill $! ...kill it! 29455 Terminated $ echo $! ...the process ID is still remembered. 29455 $ _ Here's a small example that illustrates the predefined variables used to set the command-line prompt. I set my prompt to something different by assigning a new value to PS1, and I set PS2 to a new value and illustrated an occasion where the secondary prompt is displayed. $ PS1="bash? " ...set a new primary prompt. bash? string="a long\ ...assign a string over 2 lines > string" ...">" is the secondary prompt. bash? echo $string ...look at the value of "string". a long string bash? PS2="??? " ...change the secondary prompt. bash? string="a long\ ...assign a long string. ??? string" ..."???" is new secondary prompt. bash? echo $string ...look at the value of "string". a long string bash? _ |