33.2. Shell Wrappers
A "wrapper" is a shell script that embeds
a system command or utility, that saves a set of parameters
passed to that command.
Wrapping a script around a complex command line
simplifies invoking it. This is expecially useful
with sed and awk.
A
sed or
awk script would normally be invoked
from the command line by a sed -e
'commands'
or awk
'commands'. Embedding
such a script in a Bash script permits calling it more simply,
and makes it "reusable". This also enables
combining the functionality of sed
and awk, for example piping the output of a set of
sed commands to awk.
As a saved executable file, you can then repeatedly invoke it
in its original form or modified, without the inconvenience
of retyping it on the command line.
Example 33-1. shell wrapper
#!/bin/bash
# This is a simple script that removes blank lines from a file.
# No argument checking.
#
# You might wish to add something like:
#
# E_NOARGS=65
# if [ -z "$1" ]
# then
# echo "Usage: `basename $0` target-file"
# exit $E_NOARGS
# fi
# Same as
# sed -e '/^$/d' filename
# invoked from the command line.
sed -e /^$/d "$1"
# The '-e' means an "editing" command follows (optional here).
# '^' is the beginning of line, '$' is the end.
# This match lines with nothing between the beginning and the end,
#+ blank lines.
# The 'd' is the delete command.
# Quoting the command-line arg permits
#+ whitespace and special characters in the filename.
# Note that this script doesn't actually change the target file.
# If you need to do that, redirect its output.
exit 0 |
Example 33-2. A slightly more complex shell wrapper
#!/bin/bash
# "subst", a script that substitutes one pattern for
#+ another in a file,
#+ i.e., "subst Smith Jones letter.txt".
ARGS=3 # Script requires 3 arguments.
E_BADARGS=65 # Wrong number of arguments passed to script.
if [ $# -ne "$ARGS" ]
# Test number of arguments to script (always a good idea).
then
echo "Usage: `basename $0` old-pattern new-pattern filename"
exit $E_BADARGS
fi
old_pattern=$1
new_pattern=$2
if [ -f "$3" ]
then
file_name=$3
else
echo "File \"$3\" does not exist."
exit $E_BADARGS
fi
# Here is where the heavy work gets done.
# -----------------------------------------------
sed -e "s/$old_pattern/$new_pattern/g" $file_name
# -----------------------------------------------
# 's' is, of course, the substitute command in sed,
#+ and /pattern/ invokes address matching.
# The "g", or global flag causes substitution for *every*
#+ occurence of $old_pattern on each line, not just the first.
# Read the literature on 'sed' for an in-depth explanation.
exit 0 # Successful invocation of the script returns 0. |
Example 33-3. A generic shell wrapper that writes to a logfile
#!/bin/bash
# Generic shell wrapper that performs an operation
#+ and logs it.
# Must set the following two variables.
OPERATION=
# Can be a complex chain of commands,
#+ for example an awk script or a pipe . . .
LOGFILE=
# Command-line arguments, if any, for the operation.
OPTIONS="$@"
# Log it.
echo "`date` + `whoami` + $OPERATION "$@"" >> $LOGFILE
# Now, do it.
exec $OPERATION "$@"
# It's necessary to do the logging before the operation.
# Why? |
Example 33-4. A shell wrapper around an awk script
#!/bin/bash
# pr-ascii.sh: Prints a table of ASCII characters.
START=33 # Range of printable ASCII characters (decimal).
END=125
echo " Decimal Hex Character" # Header.
echo " ------- --- ---------"
for ((i=START; i<=END; i++))
do
echo $i | awk '{printf(" %3d %2x %c\n", $1, $1, $1)}'
# The Bash printf builtin will not work in this context:
# printf "%c" "$i"
done
exit 0
# Decimal Hex Character
# ------- --- ---------
# 33 21 !
# 34 22 "
# 35 23 #
# 36 24 $
#
# . . .
#
# 122 7a z
# 123 7b {
# 124 7c |
# 125 7d }
# Redirect the output of this script to a file
#+ or pipe it to "more": sh pr-asc.sh | more |
Example 33-5. A shell wrapper around another awk script
#!/bin/bash
# Adds up a specified column (of numbers) in the target file.
ARGS=2
E_WRONGARGS=65
if [ $# -ne "$ARGS" ] # Check for proper no. of command line args.
then
echo "Usage: `basename $0` filename column-number"
exit $E_WRONGARGS
fi
filename=$1
column_number=$2
# Passing shell variables to the awk part of the script is a bit tricky.
# One method is to strong-quote the Bash-script variable
#+ within the awk script.
# $'$BASH_SCRIPT_VAR'
# ^ ^
# This is done in the embedded awk script below.
# See the awk documentation for more details.
# A multi-line awk script is invoked by: awk ' ..... '
# Begin awk script.
# -----------------------------
awk '
{ total += $'"${column_number}"'
}
END {
print total
}
' "$filename"
# -----------------------------
# End awk script.
# It may not be safe to pass shell variables to an embedded awk script,
#+ so Stephane Chazelas proposes the following alternative:
# ---------------------------------------
# awk -v column_number="$column_number" '
# { total += $column_number
# }
# END {
# print total
# }' "$filename"
# ---------------------------------------
exit 0 |
For those scripts needing a single
do-it-all tool, a Swiss army knife, there is Perl. Perl
combines the capabilities of sed and
awk, and throws in a large subset of
C, to boot. It is modular and contains support
for everything ranging from object-oriented programming up to and
including the kitchen sink. Short Perl scripts lend themselves to
embedding in shell scripts, and there may even be some substance
to the claim that Perl can totally replace shell scripting
(though the author of this document remains skeptical).
Example 33-6. Perl embedded in a Bash script
#!/bin/bash
# Shell commands may precede the Perl script.
echo "This precedes the embedded Perl script within \"$0\"."
echo "==============================================================="
perl -e 'print "This is an embedded Perl script.\n";'
# Like sed, Perl also uses the "-e" option.
echo "==============================================================="
echo "However, the script may also contain shell and system commands."
exit 0 |
It is even possible to combine a Bash script and Perl script
within the same file. Depending on how the script is invoked, either
the Bash part or the Perl part will execute.
Example 33-7. Bash and Perl scripts combined
#!/bin/bash
# bashandperl.sh
echo "Greetings from the Bash part of the script."
# More Bash commands may follow here.
exit 0
# End of Bash part of the script.
# =======================================================
#!/usr/bin/perl
# This part of the script must be invoked with -x option.
print "Greetings from the Perl part of the script.\n";
# More Perl commands may follow here.
# End of Perl part of the script. |
bash$ bash bashandperl.sh
Greetings from the Bash part of the script.
bash$ perl -x bashandperl.sh
Greetings from the Perl part of the script.
|