Bash Shell Scripts
Introduction
The Bash shell allows users to interact with the computer through a terminal window, organizing commands that tie various programs together. First developed by Brian Fox in 1987, the Bash shell seeks to incorporate numerous features from earlier shells for the Unix operating system. In particular, the Bash shell draws upon the Bourne shell (developed by Ken Thompson and then Stephen Bourne around 1977), the Korn shell (developed by David Korn in the early 1980s), and the C shell (developed by Bill Joy, based on Thompson's earlier shells).
Within a terminal window, you already have used several commands within the Bash shell. For example, the Basic Linux Commands reading discussed Bash commands, such as:
passwordsleep, history, catpwd, cd, ls, ls -l, which, whereis-
mkdir, rmdir, rm, cp, mv, more, head, pushd, popd manlpr, a2ps, lpq, lprmchmod
In this reading, we consider several additional commands, and we explore how various capabilities can be packaged to accomplish various tasks. The approach is not unlike programming in C (or Scheme), although the programming elements often are entire programs.
A Starting Example
The Bash shell provides many capabilities that are analogous to features of the C programming language (e.g., variables, if-statements, loops), but the Bash shell also allows processing with other programs. The following simple Bash script illustrates some of these possibilities.
#!/bin/bash
#clear the window
clear
#identify the path for the current directory
echo "the path to the current directory is `pwd`"
#print information on C programs,
# in order of increasing size
echo
echo 'C programs, in ascending order of size:'
ls -l *.c | sort -n -k 5
#finish
echo
echo bash script is done!
When a Bash script is typed into a file, the file must be given
"execute" permission before it can be run. Use the
chmod utility in the Terminal to set the permissions
correctly:
chmod +x bash-script-1
Once the file is appropriately edited and execute permission has been granted, one runs the program in the same way one runs any program:
./bash-script-1
Bash Script Files
A bash script is a file containing bash commands. To make the file executable, we must first take the following two steps.
-
The script file should contain the following code as its very first line:
This specifies which program (bash) should be used to interpret the commands in the script.#!/bin/bash -
The file permissions for the script should be set such that is it
executable.
chmod +x scriptname.sh
The script can then be run like any other executable file:
./scriptname.sh
Actually, we can also run a script as follows (even without making the script executable), but this is less frequently done.
bash scriptname.sh
Script variables
Variables can be created and initialized as shown below. Note that there should NOT be a space between the variable name and the assignment operator. (If the variable name has a space after it, bash will recognize it as a token, but since the variable does not yet exist, bash will assume the token is command name. It will then complain about not finding such a command.)
varname=12
To access the value in a variable, prepend a $ to the variable name. For example,
echo "Value in varname is $varname."
Arithmetic Expressions Require (( ))
The variables in a bash script are by default interpreted as text. To
get bash to interpret a value as a number, in order to do arithmetic
operations including arithmetic comparisons, you must wrap the
expression in double-parentheses. For example, to increment a
variable i by one, use the
expression((i++)) .
Conditionals and Loops
In addition to basic commands, the Bash shell includes capabilities
for conditionals (if) and loops (i.e., fora and
while).
If statements
One general syntax for an if-statement follows. As you would probably
expect, the elif and else clauses are
optional, and the conditions and commands should be replaced with
meaningful expressions. Note that the spaces that separate the
square brackets from the conditions ARE required.
if [ condition ]; then
command(s)
elif [ condition ]; then
command(s)
else
command(s)
fi
The long history of Bash is particularly evident in
the syntax allowed for if expressions. Bash allows
both, but interprets each syntax properly — but do not try to
mix and match the different versions. The following examples
illustrate acceptable Bash syntax, following two different ancestors.
| Task | Bourne shell style | Korn shell style |
|---|---|---|
numeric testv > 0 |
if [ $v -gt 0 ]; then
|
if (( $v > 0 )); then
|
numeric testv ≤ 0 |
if [ $v -le 0 ]; then
|
if (( $v <= 0 )); then
|
numeric testv < 0 and v == 0 |
if [ $v -lt 0 ]; then
|
if (( $v <= 0 )); then
|
numeric test0 ≤ v ≤ 10 |
if [ 0 -le $v -a $v -le 10 ]; then
|
if (( (0 <= $v) && ($v <= 10) )); then
|
For reference, all of these code segments are available in the Bash shell
bash-example-1.sh
Comparison Operators
Comparison operators are available in both the Bourne and Korn environments, although the syntax is different:
Korn shell: == != < <= > >= && || Bourne shell: -eq -ne -lt -le -gt -ge -a -o
String comparison is possible only with the symbols
== != < <= > >= && ||
Conditionals Regarding Files and Directories
Bash scripts are frequently written for tasks involving the creation and maintenance of files and directories because it can be much faster and easier to write a script for these tasks than to write the corresponding C programs.
There are many operators that can be used for testing conditions that
involve files: whether they exist, what kind of file they are,
etc. Here are a few. Note that you could also place the NOT operator
(!) before any of these tests to test whether the stated
condition is false.
| condition | checks whether... |
|---|---|
-f file |
file exists and is a regular file |
-d dir |
dir exists and is a directory |
-x dir |
file exists and is executable |
For example, you might write:
clist="classlist.txt"
if [ -f $clist ]; then
echo File $clist exists.
else
echo File $clist does not exist.
fi
for loops
The syntax for a for-loop follows.
for varname in value1 value2 ...
do
command(s)
done
The variable varname will take on each value in the list of values
in turn, with one iteration of the loop occuring for each value.
while loops
The syntax for a while loop follows.
while test
do
command(s)
done
Getting Input
Getting Input From stdin
The command read varname will read a value from stdin
(i.e., the terminal) and assign it to a variable
called varname. If the variable does not yet exist, it
will be created.
Note that the option -n can be used
with echo to cause it to not output a newline
character. (This is nice when printing user prompts, so the user can
enter a reponse on the same line as the prompt).
Getting Input From Commands
Sometimes one wishes to execute a bash shell command or other program and store the result in a variable. This can be done by using the tick quote, which is under the tilde key, ~ and looks like this: `. Note now it is different from an apostrophe (near the enter key), which looks like '.
As an example, one might store the number of words in a file to a variable with the following command
numWords=`wc -w`
Getting Input From Command-line Arguments
As we'll see soon, the mechanism for accessing command-line arguments in a bash script differs substantially from C. In bash, there are several variables that are automatically defined and loaded with information from the command-line as shown below.
| variable | stores... |
|---|---|
$# |
number of arguments given |
$* |
list of all arguments given |
$0 |
the name of the script |
$1 |
the first argument |
$2 |
the second argument |
etc |
For example, to verify the number of arguments given you might say:
if [ $# == 3 ]
Bash Quotes
To summarize, Bash scripts allow the use of three types of quotation marks: single quotes ('), back quotes (`), and double quotes ("). The bash shell interprets these variations in different ways.
| Quote Type | Interpretation |
|---|---|
single quotes (') |
the entire string within single quotes is taken literally, as a single entity (except the explanation point ! and the substring \newline have special meaning) |
back quotes (`) |
the characters within back quotes are considered a Linux command, to be executed before the rest of the line is evaluated. |
double quotes (") |
text within double quotes is scanned for Linux commands and
$-sign variables (described above).
|
These rules may seem complex, so a few examples may help. In what
follows, the whoami reports the name of the current
user—walker in this example.
echo 'the user is `whoami`'
the user is `whoami`
All text in single quotes is printed without evaluation.
echo "the user is `whoami`"
the user is walker
(Within double quotes, the back-quoted phrase `whoami'
is evaluated and inserted into the string before printing.)
echo "the user is whoami"
the user is whoami
(Within double quotes, but without back quotes, the Bash shell does
not recognize whoami as a Bash command.)
echo the user is `whoami`
the user is walker
(With no outside quotes, the back-quoted phrase `whoami'
is evaluated and inserted during printing.)
You can verify this yourself with
bash-script-2.
Some Additional Commands
Bash includes a huge range of commands. Here are a few more useful capabilities:
| Command | Description | Example |
|---|---|---|
cal |
display a calendar for a given year | cal 2010 |
date |
print the current time and date in various formats many options documented with man date |
date +'%I:%M %p on %A, %B %d, %Y' |
diff |
display differences in lines between two files | diff file1 file2 |
echo |
print specified text | echo hello world! |
env |
print the environmental variables currently set | env |
grep |
scan a file or other input for a specified text | env | grep home |
hostname |
return name of current workstation | hostname |
sort |
sort lines of a file | sort -n -k 12 (sort by numbers in column 12) |
users |
simple list of users | users |
who |
print list of users currently logged in | who and who -a |
whoami |
print the username of the person logged in | whoami |
ypcat password |
print user information from the password file | ypcat password | grep $USERNAME |
More information on each of these commands may be found with
the man facility (e.g., man date).
Beyond this basic documentation included here an in previous labs, many
resources are available on line. Here are a few places to begin:
- The Bash home page from the GNU Project provides a complete online manual for Bash.
- The Bash Guide for Beginners from The Linux Documentation Project provides a good introduction to the Bash shell.
- At this writing, a Google search of "bash shell introduction" produced about 2,5000,000 hits, so there is much easily-accessible material to read on this subject! (Though the quality surely varies.)
