Calling external programs
* Piping. e.g., only list files beginning with foo: ls | grep foo*
* Redirecting output. There are several ways to do this.
o ls > foo overwrites foo with the output of ls
o ls ยป foo adds the output of ls to the end of foo
o ls 2> foo overwrites foo with STDERR output of ls
o ls &> foo overwrites foo with the output of ls and STDERR output of ls
o ls 1>&2 redirects STDOUT of ls to STDERR
o …
* Chaining. First, note that by convention C programs return a 0 to indicate successful exit status, e.g.,
#include
int main(int argc, char *argv[]) {
printf(”Hello World!\n”);
return 0;
}
But a nonzero exit status indicates an failure of some kind. There are operators in Bash that use the exit status. For example, cmd || echo “error message” generates an error message if cmd fails. Also, make foo && ./foo runs foo only if the make is successful. In general, there are two ways to chain commands: (1) cmd1 || cmd2 || … || cmdn; executes until cmdi has given a nonzero return value and, (2) cmd1 && cmd2 && … && cmdn; executes until cmdi has given a zero return value.
* Sequencing. e.g., cmd1; cmd2 executes cmd1 first and cmd2 second regardless of exit status.
Hello World!
Save the following in hw.sh.
#!/bin/bash
echo Hello World
The script must have the execute permission set before it is run. Execute the file by running the following at the Bash prompt.
# chmod u+x hw.sh; ./hw.sh
Hello World!
Command-line arguments and variables
Command-line parameters provide one way for the script to access data from the shell. These reserved parameter variables start with the name of the script, $0, and are assigned positionally for each argument $i. The number of parameters is set in $#. The script below simply prints its first two arguments.
#!/bin/bash
echo $1
echo $2
The example below shows how the programmer can define variables. The variable $STR is assigned the value “argument 1: ” and then concatenated to the command-line parameter $1.
#!/bin/bash
STR=”argument 1: ”
echo $STR$1 #concatenate $STR with $1
The script prints out its first command-line argument.
# ./hw2.sh “Hello World!”
argument 1: Hello World!
There are a few general notes about user-defined variables like $STR in the above example.
* Variables can simply be used without any explicit introduction.
* Changes to variables within a script are not visible outside the script, e.g.,
# STR=”original string”
# ./hw2.sh
argument 1: Hello World!
# echo $STR
original string
* The export command makes variables visible to subscripts, but not outer scripts, e.g., suppose script s1.sh uses the variable $STR.
# export STR=”original string”
# ./s1.sh # s1.sh will see STR=”original string”
* Several built-in variables are set by the shell, e.g, PATH, HOME, etc.
* The command set prints all defined variables.
* Variables are assumed to be strings by default. Casting is applied when necessary.
Arithmetic Expressions
The straightforward way of performing arithmetic does not work as expected, e.g.
# x=1+2
# echo $x
1+2
Instead, use the double parens to perform arithmetic.
# (( i=1 ))
# (( j=$i+1 ))
# echo $j
2
Conditionals
There are several forms for branching, the simplest of which uses if statements. This script tests whether there are more than one command-line arguments.
#!/bin/bash
MIN_ARGS=1
if [ “$#” -lt “$MIN_ARGS” ]; then
echo There are more than one command-line args
else
echo Fail
fi
The following script tests to see if FILE exists and is a file that is neither directory nor device file, called a “regular file”.
#!/bin/bash
FILE=”foo”
if [ -f $FILE ]; then
echo FILE foo is a regular file
fi
Looping
The for loop is very useful, and has several forms, e.g., this prints three strings
#!/bin/bash
for v in one two three; do
echo $v
done
When run:
one
two
three
This example prints out a directory listing.
#!/bin/bash
for v in $( ls ); do
echo item: $v
done
When run:
item: foo1
item: foo2
item: foo3
C-style loops are also available.
#!/bin/bash
N=3
for (( i=1; i
done
When run:
item: 1
item: 2
The while loop is also available.
#!/bin/bash
i=1
LIMIT=3
while [ “$i” -lt “$LIMIT” ]; do
echo item: $i
(( i++ ))
done
When run:
item: 1
item: 2
Exercise
Write a bash script in the file mycat.sh that takes 2 or more arguments (call them f1, f2, … fn). Follow these guidelines.
* All arguments are filenames.
* If fewer than two arguments are given, an error message is printed to STDERR.
* If the file f1 exists (test by -e), an error message is printed to STDERR.
* If some files in f2, …, fn are not regular files, then print an error message to STDERR at the end, displaying each missing file at once. For example, if files foo1 and foo2 are missing, print “ERROR: missing files foo1, foo2”.
* Otherwise, concatenate files f2, …, fn using cat, and store the result in f1
Run some test cases to be sure the solution is correct. Say we have files f2,
foo1
foo2
and f3.
foo3
foo4
Then, ./mycat.sh f1 f2 f3 should output the following into f1.
foo1
foo2
foo3
foo4
Test your script for the error cases, e.g, having f1 exist, or having f2 not exist.







