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 lab, 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.
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.)
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. Recall that this is typically done as follows:
chmod 755 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 test a > 0 |
if [ $a -gt 0 ]; then
|
if (( $a > 0 )); then
|
| numeric test a ≤ 0 |
if [ $a -le 0 ]; then
|
if (( $a <= 0 )); then
|
| numeric test a < 0 and a == 0 |
if [ $a -lt 0 ]; then
|
if (( $a <= 0 )); then
|
| numeric test 0 ≤ a ≤ 10 |
if [ 0 -le $a -a $a -le 10 ]; then
|
if (( (0 <= $a) && ($a <= 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
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 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 ]
