sections in this module | City College of San Francisco - CS160B Unix/Linux Shell Scripting Module: Shell Basics |
module list |
Local vs. Environment Variables
When you create a variable it is local to the current shell. If you start a new process, the new process does not know the variable even exists.
A subset of your variables are copied to child processes when they are started. These variables are called environment variables.
You can place any variable in the environment by exporting it. Once a variable is in the environment, it remains there for your shell and all of its descendents. The only way you can remove a variable from the environment is to delete it (using unset) and recreate it.
A child process cannot alter the value of its parent's variables, no matter whether they are local variables or environment variables.As far as your code is concerned, there is no difference between a local and an environment variable. The only difference is whether a child process gets a copy when it starts:
$ cat showname
#!/bin/bash
echo "the value of \$Name is '$Name'"
$ Name=Greg
$ ./showname
the value of $Name is ''
$ export Name
$ ./showname
the value of $Name is 'Greg'
$
Note
that Name is not a global variable. If showname modified the value of
Name it would only affect the copy in showname, not the copy in the
parent shell. Environment variables are just used to initialize
variables for child processes.
Environment variables are normally used to hold constant system information that may be needed by a shell program. Variable data that must be provided to a shell program are usually passed in arguments.
Note: Sometimes it is not convenient to modify your environment variables just for the sake of a command you want to run. In this case, you want to set (or change) an environment variable for a command, but not to modify your variables.
You can prefix any command you run with one or more variable assignments to set environment variables for the child only.
As an example, hills has two versions of perl, an interpreter, installed. The default one, which is part of the standard Linux distro, is considerably older than the one our classes need to use. This newer version is placed in a special area so that the PATH finds that version preferentially. You can see this using the perl -version option, to show which version of perl is being used:
$ perl -version
This is perl 5, version 24, subversion 0 (v5.24.0) built for x86_64-linux
Copyright 1987-2016, Larry Wall
...
If we set a simple standard PATH for the perl command before it is run, the default installation of perl is found:
$ PATH=/usr/bin:/bin:/usr/local/bin perl -verions
This is perl, v5.10.1 (*) built for x86_64-linux-thread-multi
Copyright 1987-2009, Larry Wall
...
You can set multiple environment variables for your command when you run it. Simply place a space between each variable assignment, and between the last assignment and the command you want to run.
Remember, after you run the command, your variables have not been modified.
Assigning to variables
When you assign to a variable, you replace its value. If the variable did not previously exist, it is created. There are generally no declarations for variables.
All variables are of type String. If you assign an integer to a variable it is just a string (text) representation of the integer. The validity of the integer is not checked until the variable is used in a context that requires an integer.
Assignment to a variable uses the = sign, and there can be no space between the variable name (on the left) and the new contents (on the right). Just as in all shell contexts, spaces are significant and must be quoted:
Name=Greg # this is okay
Name=Greg Boyd # this is not okay. Try it and see what happens!
Name="Greg Boyd" # again, fine.
Variable names may include alphabetic and numeric characters, and
underscores. A variable name may not start with a number. They are
case-sensitive. There is a length limit, but it is so big it need not
be mentioned, unless the variable name is generated automatically.
Example:
Which of these variable names are legal?
Substituting variable's values
When the shell sees a $ followed by a word of text it tries to
substitue a variable with that name. The full syntax for substituting
the value
of variable FOO is ${FOO}. If there is no ambiguity about where the
name of the variable starts and ends, you can abbreviate this to $FOO.
If you try to substitute the value of a variable that does not exist, the result is the empty string.
Example:
outputs Boyd
since the name of First was misspelled when it was substituted.
Remember, substitutions are performed before the final command is run. Consider the following command
echo "My name is $FIRST $LAST"
First, the $FIRST and $LAST are replaced by their values. If FIRST is Greg and LAST is Boyd, the resulting command looks like this
echo "My name is Greg Boyd"
Then the resulting command is run.
Operators on variables
The ${} construct has a host of operators to operate on the variable's value during the substitution. We will cover the most basic ones here, and cover the pattern matching operators much later, as they can be quite confusing:
this | is substituted for |
the value of the variable FOO | ${FOO} |
the length (in characters) of the value of the variable FOO | ${#FOO} |
the value of the variable FOO if it is non-empty. If the value of FOO is empty, it aborts the shell script and prints the message on standard error. | ${FOO:?message} |
the value of the variable FOO if it is non-empty. If the value of FOO is empty, it is replaced by alternate. The value of FOO is not modified, however. (It would be left empty.) | ${FOO:-alternate} |
the value of the variable FOO if it is non-empty. If the value of FOO is empty, it is replaced by alternate. The value of FOO is also set to alternate. | ${FOO:=alternate} |
Examples:
Issues with variables
When a variable is created, it is a local variable. If you export the variable using its name (not its value!), the variable is placed in the environment (it is an environment variable). Once a variable is in the environment, it is there until it is destroyed. Remember, environment variables are copied to child processes, so whatever the value of the variable is at the time the process is started, is copied.
A variable can be destroyed using the unset directive
Name=Greg # Name is a local variableArithmetic
The external command expr can be used for shell arithmetic. Unfortunately, many of the arithmetic operators are also special characters in the shell. Consider the following simple expression, where num1 and num2 are integers:
(num1 + num2) * num1
This could be understood by expr if spaces were used appropriately:
( $num1 + $num2 ) * $num1
However, the parenthesis and the asterisk are special characters to the shell, so they must be escaped. The final command is
expr \( $num1 + $num2 \) \* $num1
You can see how ugly this could get.
The double parenthesis operator was introduced in POSIX-compliant shells to simplify arithmetic operations. Simply take any C-style arithmetic statement and enclose it in double parenthesis. The following syntax restrictions are relaxed
it is not necessary to prefix variable
names with $
to substitute their values. If the variable name appears
in a context in which the value should be used, it is substituted. The
only exception to this is positional parameters, whose name is a digit.
For example, $1 must be used to substitute parameter 1, to avoid
ambiguity with the constant 1.
the contents of (( )) are interpreted as arithmetic. Thus, *, etc., are not shell operators.
spacing restrictions are relaxed just as they are in C-style arithmetic.
Arithmetic can appear in two forms: (( )) by itself, or $(( ))
(( expression )) simply performs the arithmetic expression. If the result is to be saved, it must be saved by an assignment in expression. The double-parenthesized expression must appear by itself on a line. You could think of it as an arithmetic command.
$(( expression )) performs the expression and substitutes the result.
Examples:
The following examples all compute num1 = num1 * (num1+num2)
(( num1 = num1 * (num1 + num2)))
num1=$((num1 * (num1 + num2)))
(( num1 = $num1* ($num1+$num2)))
(( num1 *=(num1+num2)))
Note that shell arithmetic is integer arithmetic. For example
echo $(( 3 / 2 ))
1
You can use standard prefixes to indicate radixes other than decimal. A 0 prefix indicates octal, a 0x prefix indicates hexadecimal. If you want (or need) to specify the radix exactly, you can use N# as a prefix on the number, where N is the radix desired:
Example
echo $(( 2#1100 ))
12
Common Variables
Your shell process has many variables defined. Most of these are envionment variables. A few of the most commonly-used ones are below:
variable | env? | meaning | variable | env? | meaning |
HISTFILE | N | path to history file | IFS | N | delimiter characters for second tokenization of shell commands |
HISTSIZE | N | number of commands in history | HOME | Y | home directory path. You should never change the value of HOME. The shell uses it for ~ and the cd command. |
LOGNAME, USER | Y | your login name | PATH | Y | list of directories to look in to find commands |
PS1, PS2, etc | N | prompt strings | PWD | Y | path to current directory |
SHELL | Y | path to shell | TERM | Y | type of terminal (for cursor addressing) |
Prompt Strings
PS1, etc, are your prompt strings. Prompt strings are evaluated to output the prompt. There are three prompt strings, but the last one (PS3) is rarely seen.
PS1 is output as your primary prompt. PS2 is output when you enter a command and it is incomplete when you type newline:
In the example above, the primary prompt is "-bash$ " The secondary prompt is "> ". We can prove this by setting these variables:
PS1="another command? "
PS2="finish it, silly> "
After defining this, here is our example:
Since prompt strings are evaluated when the prompt is output, you can place commands and variables in them. However, this is when you must understand the word evaluated, and how understanding quoting rules can be important. (We will go over quoting rules in the next module. You may want to refer back to this section.)
Suppose you want to output the path to the current directory in your prompt string. To do this we will simply refer to our PWD variable from within our prompt string. Notice how the type of quotes we use affects how our prompt works:
$ pwd /users/gboyd $ PS1="[$PWD]$ " [/users/gboyd]$ cd /tmp [/users/gboyd]$ pwd /tmp [/users/gboyd]$ | $ pwd /users/gboyd $ PS1='[$PWD]$ ' [/users/gboyd]$ cd /tmp [/tmp]$ pwd /tmp [/tmp]$ |
The difference is due to when the $PWD variable gets evaluated and the result substituted. When it is enclosed in double-quotes, the value of $PWD is substituted when the prompt is set. This places a constant path in the prompt string. When it is enclosed in single-quotes, the prompt string contains the string [$PWD]$ When the prompt is evaluated, the current value of $PWD is substituted and the result output.
Customization of prompt strings in bash is simple through the use of special prompt string escape sequences. Some of the most popular ones are
\h, \H - hostname (short and long formats)
\t, \T, \@, \A - time formats
\w, \W - full and basename of the current working directory
\u - current user name
\s - shell name
For example, PS1='[\u@\h]<\W>(\A)$ ' gives the prompt
[gboyd@hills]<~>(17:11)$
You should always place a space at the end of your prompt string for clarity.
Other notes on standard variables
TERM - This is your terminal type. Terminal types are mostly legacy code. A value of vt100 will usually get your terminal working if it isn't set. Remember, TERM must be an envionment variable, so you must use export if you create it.
PATH - This is your search path. It is a colon-separated list of directories to look in to find commands. If you modify your search path, make sure you only append to it. For example, if you have your own directory /home/you01/bin that you place your shell scripts in and you want it to be able to run your shell scripts by just typing their name, add your directory to the end of your search path like this:
PATH=$PATH:/home/you01/bin
(You should never place a personal directory at the front of your search path!)
Prev | This page was made entirely with free software on Linux: Kompozer and Openoffice.org |
Next |