Bash Lab                
Introduction                
For this lab, you will take a small bash script called rn
,
modify it to do more things, and turn it in for credit.
                
A script                
A bash script (or more generally, a shell script) is
a series of bash commands in a file. You create the file using
an editor, such as vim or nano, and then you execute (or run) the
script, as if it were a program, because it is one.
                
Really, that’s all there is to it. Anything that you could type into an
interactive bash shell (cd, ls, pwd, cp, mkdir, rm,
make, vim, etc.), you can put into a bash script.
                
Also, bash scripts often contain other constructs more often found in
programming languages, such as if
, while
, and for
statements, and variable usage. You could use such things
interactively, but you rarely do.
                
Basic bash programming                
- Start with
#! /bin/bash
This tells the system that this is a bash script,
and not some other sort of program, such as machine language.
- Special variables:
- Name of script:
$0
- Arguments:
$1
, $2
, $3
, …
- Argument count:
$#
- Result of last command:
$?
(0 for success, >0 for failure)
- Use these variables in your script to make decisions, and to
access the arguments given by the user when they ran the script.
if (( $# == 0 ))
then
echo "I have no arguments. ☹"
fi
- Quote special characters to prevent them from acting specially:
echo Wildcard: /etc/host*
echo "Quotes protect it: /etc/host*"
Wildcard: /etc/host.conf /etc/hostname /etc/hosts
Quotes protect it: /etc/host*
- Variables are evaluated inside double quotes:
echo "I am $USER"
I am cs253
- Variables are not evaluated inside single quotes:
echo 'Cost: $0.24'
Cost: $0.24
- Use
$
to get the value of a variable; not when assigning it:
alpha="foo bar"
echo "I say $alpha"
I say foo bar
- Capture command output with
$(
…)
:
now=$(date)
echo "Current time: $now"
Current time: Thu Nov 21 23:04:29 MST 2024
- Numeric variables with
let
:
let beta=2+2
echo "beta is $beta"
beta is 4
if condition
then
statements
fi
if [[ -e /etc/hostname ]] # Does the file exist?
then
cat /etc/hostname # Let’s see it!
fi
beethoven
- A more complex conditional:
if condition
then
statements
else
statements
fi
if condition
then
statements
elif different-condition
then
statements
else
statements
fi
while condition
do
statements
done
for variable in list
do
statements
done
- The list can be an explicit list:
for person in John Paul George Ringo
do
echo $person was one of the Beatles
done
John was one of the Beatles
Paul was one of the Beatles
George was one of the Beatles
Ringo was one of the Beatles
- The list can be a filename pattern:
for song in *.mp3
do
echo Copying the file $song
cp $song ~/songs/
done
((
arithmetic condition ))
, like C++:
if (( age >= 21 && money > 4.00 ))
then
echo "You can buy a beer!"
fi
while [[ $suffix = "txt" ]]
do
somehow change the suffix
done
# Is this an executable file?
if [[ -x index.txt ]]
then
echo index.txt is executable
fi
if [[ -r $filename ]]
then
echo $filename is readable
fi
if [[ -e $filename ]]
then
echo $filename exists
fi
- Any command that succeeds or fails:
if grep -q foobar $datafile
then
echo "$datafile contains the string \"foobar\""
fi
- Spaces matter:
- Good:
if [[ $suffix = "txt" ]]
- Bad:
if[[$suffix="txt"]]
- Lines matter:
then
, else
, elif
, fi
, do
, and
done
must each be on their own line.
- Routing output:
|
connects output of first command to input of second command:
grep "foo.*bar" filename | sort
>
sends standard output (non-error output) to a file:
grep "^foo" filename >results
>&2
sends standard output to standard error:
echo "$0: Don’t do that!" >&2
- Termination:
exit
(or falling off the end) terminates the script.
exit 0 # stop the script; indicate success
exit 1 # stop the script; indicate failure
Script                
Here is a small bash script. It changes file suffixes:
                
#! /bin/bash
old_suffix=$1
new_suffix=$2
for f in *.$old_suffix
do
new_name=${f%.*}.$new_suffix
echo Rename $f to $new_name
done
You might use it like this, to rename all of your C files
(ending in .c
) to be C++ files (ending in .cpp
):
                
chmod +x rn
./rn c cpp
The chmod command makes the script executable, so we can treat
it as a program. You only need to do that once.
                
The leading ./
in ./rn
means that we want to execute the file
rn
that’s in the current directory, not some other file named rn
somewhere else.
                
Copy the script, above, to the file rn
. No suffix—just the
two-character filename rn
with nothing after. You will modify
rn
, and turn it in for credit.
                
For this lab, you should:
                
- Understand how the script works.
You don’t have to write any of these down, you just have to do them.
All that you turn in is the file
rn
.
- Understand why we said
./rn
as opposed to just rn
.
- Copy & paste what I gave you into your own file
rn
, and try it out.
Make sure that the first two characters in the script are #!
,
with nothing before them.
- Make it actually rename the file, rather than just saying so.
- Add a usage message if too many or too few arguments are given.
A usage message is a message that tells the user what arguments
to give to this script, if an improper number of arguments (including none)
are given.
- Send the usage message to standard error.
- Complain (to standard error) if a file can’t be renamed.
- Not clobber existing files. That is, if we run the script like this:
./rn foo bar
- and both
alpha.foo
and alpha.bar
exist, the script should complain and refuse to do anything else.
For extra fame & glory (but no extra points), you could:
                
- Add a
-n
option that doesn’t rename,
but just says what it would do
- Add a
-v
option that renames verbosely
- Complain if no files have the given suffix
- Make it work for filenames and suffixes that contain spaces
- Make it work for suffixes that are wildcards (whatever that means)
How to submit your work:                
In Canvas, check in the
file
rn
to the assignment “Lab02”.
It’s due 10:00:00ᴘᴍ MT Saturday, with a 24-hour late period for a 25% penalty.
                
How to receive negative points:                
Turn in someone else’s work.