Hello, and welcome to episode number eight of the Software Carpentry lecture on the Unix shell. In this episode, we'll have a look at shell variables.
As you've heard several times by now, we're looking at how to interact with a computer using a command-line shell.
The shell is just a program…
…and like other programs, it has variables.
Those variables control its execution, and by changing their values, you can change how the shell and other programs behave.
Let's start by running the command set
and looking at some of the variables in a typical shell session. As you can see, there are quite a few—in fact, four or five times more than what's shown on this media.
Using set
to show things might seem a little strange, even for Unix, but if you don't give it any arguments, it might as well show you things you could set.
Every variable has a name. By convention, variables that are always present are given upper-case names.
All shell variables' values are strings.
It's up to programs to convert these strings to other types when necessary.
For example, if a program wanted to find out how many processors the computer had, it would convert the NUMBER_OF_PROCESSORS
variable from a string to an integer.
Some variables store lists of values. Here, the convention is to use a colon ':' as a separator. If a program wants the individual elements of such a list, it's the program's responsibility to split the variable's string value into pieces.
Let's have a closer look at one of the most important of those list-valued variables, PATH
. Its value defines the shell's search path, i.e., the directories that the shell looks in for runnable programs.
If you recall from a couple of episodes ago, if we type a command like ./analyze
, with a specific directory in the path, the shell runs the program that path specifies.
Similarly, if we type /bin/analyze
, the shell runs that specific program: we've provided a specific path, so it knows what to do.
But what should the shell do if we just type analyze
? There are at least two things it could run: how should it choose?
Its rule is simple. The shell checks each directory in the PATH
variable in turn, looking for a program with the rqeuested name in that directory. As soon as it finds a match, it stops searching and runs the program.
To show how this works, here are the components of PATH
broken out one per line.
On our computer, there are actually three programs called analyze
in three different directories.
Since the shell searches the directories in order, it finds the one in /bin
, not either of the others.
Notice that it will never find the program /users/vlad/analyze
, since the directory /users/vlad
isn't in our path.
Before we explore variables any further, let's introduce one more command: echo
. All it does is print out its argument.
This doesn't sound very exciting, but we can use it to show variables' values.
First, let's make sure it works. Yup: echo hello transylvania!
prints hello transylvania!
as promised.
Now let's try to show the value of the variable HOME
with echo HOME
.
Whoops: that just prints "HOME".
Let's try this instead: echo $HOME
.
The dollar sign tells the shell to replace the variable's name with its value.
This works just like wildcards: the shell does the expansion before running the program we've asked for.
Thanks to this expansion, what we actually run is echo /home/vlad
, which shows us the variable's value.
Creating a variable is easy: just assign a value to a name using "=".
Changing a value is equally easy: just assign the new value.
Here, we set our secret identity to be Dracula
, check it, change it to Camilla
, and check again.
It's important to note, though, that assignment only changes a variable's value in the current shell, not in any other shells that are currently running, or in any shells that are started later.
Let's go back and set our secret identity once again.
Once it's set, let's run a fresh copy of the shell by typing the command bash
.
We now have two copies of the shell running: the original, shown in green, and its child, shown in orange.
If we echo $SECRET_IDENTITY
in the child shell, nothing is printed, because the variable doesn't have a value.
If we exit the child shell and return to the original…
…we can see that yes, the variable does exist.
If we really want the shell to pass a variable to the processes it creates, we must use the export
command.
Let's try the secret identity example again. After giving SECRET_IDENTITY
a value, we give the shell the command export SECRET_IDENTITY
. (Note, by the way, that it's not export $SECRET_IDENTITY
with a dollar sign: if we typed that, the shell would expand SECRET_IDENTITY
, and our export
command would actually be export Dracula
, which would do nothing, because there's no variable called Dracula
.)
Now let's run a new shell…
…and type echo $SECRET_IDENTITY
. Yup: there's our variable.
And of course, exiting brings us back to our original shell.
If we want to set some variables' values automatically every time we run a shell, we can put the command to do this in a file called .bashrc
in our home directory. The '.' character at the front prevents ls
from listing this file unless we specifically ask it to using -a
—we normally don't want to worry about it—and the "rc" at the end is an abbreviation for "run control", which meant something really important decades ago, and is now just a convention everyone follows without understanding why.
For example, here are two lines in Vlad's .bashrc
file. These two lines create the variables SECRET_IDENTITY
and BACKUP_DIR
, give them values, and export them so that any programs the shell runs can see them as well.
And while we're here, it's also common to use the alias
command to create shortcuts for things we frequently type.
For example, we can define the alias backup
to run /bin/zarble
with these arguments. Notice that these arguments include references to some variables, so that if we want to change where we put our backups, we only have to change one variable's value in one place.
As you can see, aliases can save us a lot of typing, and a lot of typing mistakes.
In our next episode, we'll have a look at how to connect to other machines securely.