sections in this module City College of San Francisco - CS160B
Unix/Linux Shell Scripting
Module: Shell Basics
module list

Variables and Arithmetic

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?

  1. 1Way
  2. WayOut
  3. way-to-go
  4. For_Sale
  5. _Name
(ans: b,d, and e)

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:

First=Greg
Last=Boyd
echo "$Firstt $Last"

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:

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

$ FOO=hello
$ echo ${#FOO}
5

$ FOO=

$ echo ${FOO}

$ echo ${FOO:?"help, where is FOO?"}
bash: FOO: help, where is FOO?
$
$ echo ${FOO:-"FOO was empty"}
FOO was empty
$ echo $FOO

$ echo ${FOO:="FOO was empty"}
FOO was empty
$ echo $FOO
FOO was empty
$

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 variable
export Name    # now Name is an environment variable
unset Name     # Name is no longer a variable
Name=Sandra    # the new variable Name is a local variable.

Arithmetic

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

Arithmetic can appear in two forms: (( )) by itself, or $(( ))

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:

variableenv?meaningvariableenv?meaning
HISTFILENpath to history fileIFSNdelimiter characters for second tokenization of shell commands
HISTSIZENnumber of commands in historyHOMEYhome directory path. You should never change the value of HOME. The shell uses it for ~ and the cd command.
LOGNAME,
USER
Yyour login namePATHYlist of directories to look in to find commands
PS1, PS2, etcNprompt stringsPWDYpath to current directory
SHELLYpath to shellTERMYtype 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:

-bash$ VAR="hello there. how are
> you"
-bash$

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:

another command? VAR="hello there, how
finish it, silly> are you?"
another command?

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

Copyright 2016 Greg Boyd - All Rights Reserved.

Document made with Kompozer