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

Commands Files vs. Shell Scripts

Often, we want to automate a procedure in Linux by executing a set of commands that have been previously written and saved in a file. Whether we refer to this file as a commands file or as a shell script depends on how the commands in the file get executed.

Both commands files and shell scripts start as a file of Unix commands. Suppose we have such a file named mycmds in the current directory. To execute those commands we must give them to a shell.

One way to give them to a shell is to execute them in our current shell. This operation is called sourcing the commands file, or, in our terminology, using it as a commands file. The traditional way of sourcing a file of commands is to use the dot operator:

. ./mycmds

Because the dot operator can be difficult to see, an alternate method from the C shell has been adopted in bash. It replaces the dot operator with the word source:

source ./mycmds

hence the term "sourcing". The two techniques are identical. However, the source directive may not be available in other Bourne-type shells.

Those of you who are programmers can think of this as an include directive, and that is exactly what it is: the lines from mycmds are read and executed by your shell just as if you typed them in at the prompt.

Let's see how this works. First, take a look at mycmds:

$ cat mycmds
echo "hello from mycmds"
NAME=Greg
cd /tmp
$

Before we start, here are a couple of pieces of information about our current environment:

$ echo $NAME

$ pwd
/home/gboyd
$

Now let's source mycmds

$ . ./mycmds
hello from mycmds

After sourcing mycmds, notice how our current environment has been modified:

$ echo $NAME
Greg
$ pwd
/tmp
$

The result was just as if we had typed the commands into the current shell (i.e., at the prompt). Our shell's environment (variables and current directory) were modified by the commands in mycmds. This can be useful in two instances:

Usually, modification of our shell's environment by commands from an external file is not desirable. Usually, we want to protect our current shell from the effect of the commands in a file such as mycmds. In order to isolate our shell from the effects of the commands in our file we must execute those commands in a separate shell. You can do this in two ways:

bash < mycmds
In this case, a new shell is started, the commands from mycmds are executed in it, and that new shell exits.
./mycmds

This last mechanism is what we refer to as running a shell script. Let's see again what is necessary to convert mycmds to a shell script

  1. First, add the interpreter directive. This first line tells the system how to execute your script. The line begins with #! as the first two characters on the line, followed by the path to the program that you want to interpret the file, in our case bash. The best path to use for bash is /bin/bash, so the first line should be 

#!/bin/bash

Note that the # must be at the beginning of the line. (Remember, a # indicates a comment, so this is a special non-comment comment. Some of us have seen these in other languages such as javadoc directives and directives in html comments.)

  1. Next, make your program executable by adding x permission.
chmod +x mycmds
  1. Then execute it directly:
./mycmds

Here mycmds executes in a separate shell, isolating your shell's environment from any changes. The mycmds process is called the child shell (or subshell) and the shell that started mycmds is the parent shell.

Notice that while some extra preparation is needed before we can run mycmds as a shell script, the thing that decides whether it is a commands file or a shell script is how we run it. A shell script is executed directly. A commands file is read into the current shell. The same file can be used as both a shell script and a commands file. (The shebang directive is only a directive when we execute the file. Otherwise, it is just a comment!)

Let's do the same experiment as before and execute the commands in mycmds as a shell script

$ ls -l mycmds
-rwx--x--x 1 gboyd users 55 Oct 13 12:36 mycmds
$ cat mycmds
#!/bin/bash
echo "hello from mycmds"
NAME=Greg
cd /tmp
$ echo $NAME

$ pwd
/home/gboyd
$ ./mycmds
hello from mycmds
$ echo $NAME

$ pwd
/home/gboyd
$

Variables and shell scripts

Any shell you run has a lot of variables predefined. These variables may be broken into two categories: local variables and environment variables.

Normally, local variables only affect the shell that sets them. If that shell starts another process (such as runs a shell script), the second process (the child process) does not "see" the variable.

Environment variables are different: any variable that is in the environment  is copied to the new process when it starts. Note that these variables are not global! They are simply copies. This is the standard mechanism when running a shell script - the shell script runs in a new process and only gets copies of the environment variables.

Commands files are different, however. Executing a file as a commands file (by sourcing it) is the same as typing the commands into your current shell. Thus, any variable set in the commands file becomes your variable. Additionally, if your commands file modifies a variable, your shell's environment is affected. Here there is no distinction between local and environment variables.

We will discuss variables of both types more in the next module.

Outputting messages from your shell script

As you know, your shell script can output a message using echo. echo outputs its arguments to standard output. When using echo, you should always enclose the output in some kind of quotes. We will discuss quoting rules in the next chapter. 

echo normally terminates its output by adding a newline character. If you want to suppress this behavior, add the -n option:

echo 'hello'
echo 'there'

hello
there


echo -n 'hello ' # note the space after hello
echo 'there'

hello there

Temporary files

From time to time your shell script must create a temporary file. If your shell script is functioning in the real world you must ensure that any temporary file it creates cannot conflict with user files, and that you delete any temporary file you create after you are finished with it. One way to minimize any risk of conflict with user files is to encode your current process' process-id into the name of your temporary files. This has the added benefit of allowing multiple users to use your shell script at the same time, even if they are connected to the same directory. 

You can substitute the process id of the current shell process (your shell script) in a file name by using the $ variable. For example, if my pid is 4256, I could create a temporary file to hold the output of the command foo like this

foo > temp.$$

The real name of my temporary file would then be temp.4256. Before my shell script exits I could then remove my temporary file

rm -f temp.$$

Your PATH

You may have noticed that we ran our shell script mycmds by specifying the current directory: ./mycmds  This was necessary since the directory that contained mycmds may not have been in our PATH. The PATH is simply a variable that contains a list of directories that are searched to find commands. Thus, when you issue a command such as

cat

the shell must first find an executable named cat. To find it, it searches through the directories specified in your PATH variable in order. The first instance of an executable named cat is used.

If the directory we were currently in (the one that contained mycmds) was in our PATH (i.e., the directory was specified as one of the directories to search), we could have just used the name of the file instead of having to specify where it is. (Of course, this risks finding a different mycmds executable somewhere else.)

You can examine your PATH using echo $PATH . Try it.

Startup Files

When bash starts, it initializes itself by sourcing certain files. Several of these are not under your control - they are available for the system administrator to initialize everyone's environment correctly. However, a trio of startup files are under your control. They are in your home directory and are owned by you. Here is how these are sourced:

~/.bash_profile
This file is sourced when you login at the command-line (via ssh). On RH7 systems, it is not sourced when you login at the graphical console.
~/.profile
This file is sourced when you login at the graphical console on RH7 systems. It is also sourced when you login at the command-line (via ssh) if you do not have a ~/.bash_profile file)
~/.bashrc
This file is sourced when you start a non-login shell. This occurs when running scp, and when running ssh and having it just execute a command. A non-login shell is also started when you type bash at the command-iine.
$BASH_ENV file
If the environment variable BASH_ENV is set, that file is sourced by shell scripts. If the BASH_ENV variable is set, it is usually set to ~/.bashrc


Prev This page was made entirely with free software on Linux:  
Kompozer
and Libreoffice   
Next

Copyright 2016 Greg Boyd - All Rights Reserved.

Document made with Kompozer