Section 6.3. Variables


[Page 205 (continued)]

6.3. Variables

Bash allows creation and use of shell variables for the following purposes:

  • Value assignment and access

  • Defining and using lists of values

  • Testing a value or for existence of a variable

  • Reading or writing a variable's value

6.3.1. Creating/Assigning a Simple Variable

To assign a value to a simple variable, the syntax is similar to that of other shells (Figure 6-1).

Figure 6-1. Example of assigning a simple variable.

{name=value}+


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).

Figure 6-2. Example of the set built-in to display shell variables and values.

Shell command: set

The set built-in displays all variables set in the shell.



[Page 206]

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.

Figure 6-3. Some useful set built-in options.

Option

Meaning

-o allexport | -a

Export all created or modified variables and functions.

-o emacs

Set command edit style to behave like emacs.

-o ignoreeof

Interactive shell will not exit on EOF (e.g., if you typed Control-D by accident).

-o noclobber | -C

Prevent output redirection from overwriting existing files.

-o noglob | -f

Disable filename substitution (a.k.a. globbing).

-o posix

Cause Bash behavior to always adhere to the POSIX 1003.2 Shell standard.

-o verbose | -v

Print shell input lines as they are read (useful for debugging scripts).

-o vi

Set command edit style to behave like vi.


6.3.2. Accessing Simple Variables

Figure 6-4 lists the methods Bash supports for accessing the value of simple variables.

Figure 6-4. Accessing the value of a simple variable.

[Page 207]

Syntax

Action

$name

Replaced by the value of name.

${name}

Replaced by the value of name. This form is useful if the expression is immediately followed by an alphanumeric that would otherwise be interpreted as part of the variable name.

${name-word}

Replaced by the value of name if set, and word otherwise.

${name+word}

Replaced by word if name is set, and nothing otherwise.

${name=word}

Assigns word to the variable name if name is not already set, and then is replaced by the value of name.

${name?word}

Replaced by name if name is set. If name is not set, word is displayed to the standard error channel and the shell is exited. If word is omitted, then a standard error message is displayed instead.

${#name}

Replaced by the length of the value of name.

${#name[*] }

Replaced by the number of elements in the array name.

${name:+word }

${name:=word }

${name:?word }

${name:+word }

Work like their counterparts that do not contain a :, except that name must be set and non-null instead of just set.

${name#pattern}

${name##pattern}

Removes a leading pattern from name. The expression is replaced by the value of name if name doesn't begin with pattern, and with the remaining suffix if it does. The first form removes the smallest matching pattern, and the second form removes the largest matching pattern.

${name%pattern}

${name%%pattern}

Removes a trailing pattern from name. The expression is replaced by the value of name if name doesn't end with pattern, and with the remaining prefix if it does. The first form removes the smallest matching pattern, and the second form removes the largest matching pattern.



[Page 207]

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. 
[Page 208]
Wed May 4 06:56:51 CST 2005 $ _


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 
[Page 209]
/home/glass $ echo ${PWD#$HOME/} ...remove leading $HOME/ dir1 $ fileName=menu.sh ...set a variable. $ echo ${fileName%.sh}.bak .. .remove trailing ".sh" menu.bak ...and add ".bak". $ _


6.3.3. Creating/Assigning a List Variable

List 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.

Figure 6-5. Example of the declare shell command.

Shell command: declare [-ax] [listname]

If the named variable does not already exist, it is created. If an array name is not specified when -a is used, declare will display all currently defined arrays and their values. If the -x option is used, the variable is exported to subshells. declare writes its output in a format that can be used again as input commands. This is useful when you want to create a script that sets variables as they are set in your current environment.


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 Variables

Once 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).

Figure 6-6. Accessing the value(s) of a list variable.

${name[index]}

Access the indexth element of the array $name.

${name[*]} or ${name[@]}

Access all elements of the array $name.

${#name[*]} or ${#name[@]}

Access the number of elements in the array $name.



[Page 210]

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 Lists

You 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:


[Page 211]

$ 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 lists

List variables can be deallocated or destroyed using the unset built-in to Bash (Figure 6-7).

Figure 6-7. Description of the unset shell command.

Shell command: unset name

unset name[index]

Deallocates the specified variable or element in the list variable.


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 Input

The read command allows you to read variables from standard input (Figure 6-8).

Figure 6-8. Description of the read shell command.

Shell Command: read { variable }+

read reads one line from standard input and then assigns successive words from the line to the specified variables. Any words that are left over are assigned to the last-named variable.


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. $ _ 



[Page 212]

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 Variables

In 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).

Figure 6-9. Description of the export shell command.

Shell Command: export { variable }+

export marks the specified variables for export to the environment. If no variables are specified, a list of all the variables marked for export during the shell session is displayed.


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).

Figure 6-10. Description of the env command.

Utility: env { variable=value }* [ command ]

env assigns values to specified environment variables, and then executes an optional command using the new environment. If variables or command are not specified, a list of the current environment is displayed.


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. 
[Page 213]
$ DATABASE=/dbase/db ...create a local variable. $ export DATABASE ...mark it for export. $ export ...note that it's been added. export DATABASE export TERM $ env ...list the environment. DATABASE=/dbase/db HOME=/home/glass LOGNAME=glass PATH=:/bin:/usr/bin SHELL=/bin/bash TERM=xterm USER=glass $ bash ...create a subshell. $ echo $DATABASE ...a copy was inherited. /dbase/db $ ^D ...terminate subshell. $ _


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).

Figure 6-11. Example of the set built-in to export all variables.

Shell command: set -o allexport

Tell the shell to export all variables to subshells.


6.3.9. Read-Only Variables

The readonly command allows you to protect variables against modification (Figure 6-12).

Figure 6-12. Description of the readonly shell command.

Shell Command: readonly { variable }*

readonly makes the specified variables read-only, protecting them against future modification. If no variables are specified, a list of the current read-only variables is displayed. Copies of exported variables do not inherit their read-only status.


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 
[Page 214]
$ readonly password ...protect it. $ readonly ...list all read-only variables. readonly password $ password=Phoombah ...try to modify it. password: is read only $ export password ...export the variable. $ password=Phoombah ...try to modify it. password: is read only $ bash ...create a subshell. $ readonly ...the exported password is not read-only. $ echo $password ...its value was copied correctly. Shazam $ password=Alacazar ...but its value may be changed. $ echo $password ...echo its value. Alacazar $ ^D ...terminate the subshell. $ echo $password ...echo original value. Shazam $ _


6.3.10. Predefined Variables

Like most shells, Bash defines some variables when it starts (Figure 6-13).

Figure 6-13. Bash predefined variables.

[Pages 215 - 216]

Name

Value

$-

The current shell options assigned from the command line or by the built-in set commanddiscussed later.

$$

The process ID of this shell.

$!

The process ID of the last background command.

$#

The number of positional parameters.

$?

The exit value of the last command.

$@

An individually quoted list of all the positional parameters.

$_

The last parameter of the previous command.

$BASH

The full pathname of the Bash executable.

$BASH_ENV

Location of Bash's startup file (default is ~/.bashrc).

$BASH_VERSINFO

A read-only array of version information.

$BASH_VERSION

Version string.

$DIRSTACK

Array defining the directory stack (discussed later).

$ENV

If this variable is not set, the shell searches the user's home directory for the ".profile" startup file when a new login shell is created. If this variable is set, then every new shell invocation runs the script specified by ENV.

$EUID

Read-only value of effective user ID of user running Bash.

$HISTFILE

Location of file containing shell history (default ~/.bash_history).

$HISTFILESIZE

Maximum number of lines allowed in history file (default is 500).

$HISTSIZE

Maximum number of commands in history (default is 500).

$HOSTNAME

Hostname of machine where Bash is running.

$HOSTTYPE

Type of host where Bash is running.

$IFS

When the shell tokenizes a command line prior to its execution, it uses the characters in this variable as delimiters. IFS usually contains a space, a tab, and a newline character.

$LINES

Used by select to determine how to display the selections.

$MAILCHECK

How often (seconds) to check for new mail.

$OLDPWD

The previous working directory of the shell.

$OSTYPE

Operating system of machine where Bash is running.

$PPID

The process ID number of the shell's parent.

$PPID

Read-only process ID of the parent process of Bash.

$PS1

This contains the value of the command-line prompt, and is $ by default. To change the command-line prompt, simply set PS1 to a new value.

$PS2

This contains the value of the secondary command-line prompt that is displayed when more input is required by the shell, and is > by default. To change the prompt, set PS2 to a new value.

$PS3

The prompt used by the select command, #? by default.

$PWD

The current working directory of the shell.

$RANDOM

A random integer.

$REPLY

Set by a select command.

$SHLVL

Level of shell (incremented once each time a Bash process is started, it shows how deeply the shell is nested).

$UID

Read-only value of user ID of user running Bash.



[Page 216]

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? _ 





Linux for Programmers and Users
Linux for Programmers and Users
ISBN: 0131857487
EAN: 2147483647
Year: 2007
Pages: 339

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net