Shell and Environment Variables
Steven Zeil
In any programming language, we expect to have variable names. The commands that you type in via a command shell constitute a programming language, though you might not think of it as one, and so it should not come as too big a surprise to discover that command shells have variables.
1 Setting and Retrieving Shell Variable Values
A typical shell variable name begins with an alphabetic character and continues with zero or more alphanumeric characters. Oddly enough, when we want to get the value of a shell variable, we add a $ to the front of it.
Example 1: Try this:Log in and enter the following commands.
A=hello echo $A
and the
echo
command will produce the string “Hello”.
All shell variables hold strings, although in selected instances we may be able to interpret those strings as numbers. It all really depends on the commands we are using. If you place a shell variable into a command at a position where the command expects a number, then it will be treated as a number.
Example 2: Try ThisGive the following commands:
cd ~/playing ls ~ > 1.txt cat 1.txt one=1 head $one.txt head -n $one 1.txt
In the next-to-last command, we use the shell variable as a string, part of the filename. In the final command, we used the variable in a position where the head command expects to find a number, and so it was treated as one.
Caution: when writing commands that involve environment variables, it helps to keep in mind the different forms of quoting in Unix shells, especially the difference between ‘single quotes’ and “double quotes”.
Example 3: Try ThisGive the following commands.
cd ~/playing date > 1.dat ls > 2.dat A=1.dat 2.dat echo $A A="1.dat 2.dat" echo $A echo "$A" echo '$A' head -n 1 $A head -n 1 "$A" head -n 1 '$A'
Some of these commands may give error messages. Study the messages carefully until you understand what “went wrong”.
1.1 Shell Variables and Backticks
The use of backticks to insert the output of one command into another is often exploited to assign environment variables.
Example 4: Try ThisGive the following commands
Today=`date` echo $Today Words=`grep ^ze /usr/share/dict/words` echo $Words echo $Words | wc
Because many Unix commands function as “filters”, taking input from standard in and producing output on standard out, we can use pipes within backticks to alter the values that would be stored in a variable.
Example 5: Try ThisGive the following commands
echo $USER uc=`echo I am $USER | tr a-z A-Z` echo $uc nv=`echo I am $USER | sed -e "s/[aeiou]/./ig"` echo $nv
1.2 Manipulating File Paths
A common use of the combination of environment variables and backticks is to pull apart “pieces” of a file path.
The following commands are commonly used for this purpose:
basename
filepath: Prints the last part of a path, just after the final /
dirname
filepath: Extracts the part of a path just before the final /
, or prints .
if the path has no /
s
readlink -f
filepath: Prints the “canonical form” of the file path — the absolute path to the file with no unnecessary steps.
Example 6: Try ThisGive the following commands:
cd ~ echo /home/$USER/playing basename /home/$USER/playing basename ~/playing basename playing basename . dirname /home/$USER/playing dirname ~/playing dirname playing dirname . readlink -f /home/$USER/playing readlink -f ~/playing readlink -f playing readlink -f .
These three commands aren’t generally something you would bother with when typing commands directly at the command line. But they can be used with backticks to put useful information into environment variables.
Example 7: Try ThisGive the following commands:
cd ~ myFile=~/playing/games/math.h ls -l $myFile myDir=`dirname $myFile` echo $myDir ls -l $myDir myDir=~/playing/games/.. ls -l $myDir basename $myDir dirname $myDir
Now, if we, as “intelligent” programmers, understand that
~/playing/games/..
is “really” just an awkward way of saying~/playing
. But thebasename
anddirname
commands just aren’t that smart. That’s where thereadlink
command comes into play. It not only turns relative paths into absolute paths, it “canonicalizes” the path by getting rid of steps like “../
” or “./
”.Give the following commands:
myDir2=`readlink -f $myDir` echo $myDir2 ls -l $myDir2 basename $myDir2 dirname $myDir2
This combination of the directory manipulation commands, backticks, and environment variables, often proves useful when writing scripts, the subject of the final lesson in this course.
2 The Environment
The scope rules for shell variables are a bit odd. Most variables are local to the process where they are assigned. For example, look at the following (‘>’ is the prompt for a new command).
> A=hello
> echo $A
hello
> sh
> echo $A
A: undefined variable
> exit
> echo $A
hello
We set A
to a value and then , using echo
, printed it. In the next line, we start another copy of the shell running (sh or csh). This runs as a separate process (the old one is temporarily suspended). This new “child” process does not inherit the variable A
, so when we try to print it, we are told that A
is undefined. The exit
command shuts down the child process, returning us to the original (parent) process where we had previously defined A
, and so we were able to print it again.
This means that, normally, any environment variables that we set in this fashion will have no effect at all on any subsequent commands or programs that we launch (because all commands and programs are run as new, separate processes). Setting environment variables like this affects only the command shell in which we do it, so they can effect how that shell interprets what we type before it launches the command.
If we prefer, we can make a variable exported, meaning that its value will be seen by child processes. In sh
and bash
this is done by naming the variable in an export
command.
> B=goodbye
> export B
> echo $B
goodbye
> sh
> echo $B
goodbye
> exit
> echo $B
goodbye
The Unix environment is the collection of all shell variable values that have been imported from a parent process. Such inherited shell variables are called environment variables. Even when you first log in, your shell may inherit a number of environment variables from the process that manages user logins.
Many Unix programs rely on exported shell variables to control or modify their behavior. Examples that may be familiar include:
- TERM
- Way back when we were learning to log in with ssh, we had to set the
TERM
variable to indicate what kind of terminal our text-mode ssh client was emulating. Many Unix programs use this setting to determine what control character sequences will work on our display.
- DISPLAY
- The
DISPLAY
variable is used by X applications to determine where to send the windows and graphics for display to the person running the application.
- SHELL
- This variable saves the name of the command shell program being used to interpret your typed-in commands.
Example 8: Try ThisThe env command lists all environment and shell variables active in your current process. Give the command
env | more
and page through the list (it may be quite long). Can you guess the meaning/purpose of most of these?
2.1 The $PATH
A particularly important environment variable is PATH
. This determines what programs you can execute without typing in a full path name. If you type a command that is not a built-in shell command, and does not contain a ‘/’, then the shell looks at each directory listed in $PATH
to see if the program you have requested can be found there. For example, suppose you have compiled a C++ program and produced a new program, yourProgram
, in your current working directory. Some people will be able to execute the program this way:
yourProgram
while others will have to do it like this:
./yourProgram
The difference stems from whether your account has been set up so that your working directory (.
) is in your $PATH
. If it is, then you can use the first form. If it is not, you must use the second form. (Some people consider it a bit of a security risk to have .
in your $PATH
, arguing that you could get spoofed into doing some very strange things if someone had deposited some malicious programs into your working directory under innocuous names like “ls
” or “cp
”. My own feeling is that the threat here is pretty small.) To see your path, just give the command
echo $PATH
to print it, just as you would print any environment variable.
Adding additional directories to your $PATH
is one of the more common customizations that people make to their Unix environments. This lets them set up special directories full of customized commands and frequently-used programs.