Cookbook
A Cookbook of Shell Scripts - Wicked Shell Scripts, 2d Edition
You should browse the table of contents of this book and use the shell scripts contained within off the shelf if possible.
- GitHub: https://github.com/hamelsmu/wicked_cool_shell_scripts_2e/
- Link to book on GitHub: https://github.com/hamelsmu/wicked_cool_shell_scripts_2e/blob/master/WickedCoolShellScripts2E.pdf
- Book: https://nostarch.com/wcss2
Things Learned From The Cookbook
In addition to just using the library of shell scripts, I also learned the following bash tidbits from this book.
shift
and $#
pop args off and count args
shift.sh
#!/bin/bash
while (( $# )); do
echo "process args: $1"
shift
done
Results in:
$ ./shift.sh foo bar bash
process args: foo
process args: bar
process args: bash
Using shift for CLI options:
#!/bin/bash
# newquota--A frontend to quota that works with full-word flags a la GNU
# quota has three possible flags, -g, -v, and -q, but this script
# allows them to be '--group', '--verbose', and '--quiet' too:
flags=""
realquota="$(which quota)"
while [ $# -gt 0 ]
do
case $1
in
--help) echo "Usage: $0 [--group --verbose --quiet -gvq]" >&2
exit 1 ;;
--group ) flags="$flags -g"; shift ;;
--verbose) flags="$flags -v"; shift ;;
--quiet) flags="$flags -q"; shift ;;
--) shift; break ;;
*) break; # done with 'while' loop!
esac
done
exec $realquota $flags "$@"
$*
collect all arguments
shift2.sh
#!/bin/bash
for var in $*; do
echo $var
done
Results in:
$ ./shift2.sh foo bar bash
process args: foo
process args: bar
process args: bash
Multi Option Case Statement
while read command args
do
case $command
in
quit|exit) exit 0 ;;
help|\?) show_help ;;
scale) scale=$args ;;
*) scriptbc -p $scale "$command" "$args" ;;
esac
/bin/echo -n "calc> "
done
Another example of case statement
case $1 in
1 ) month="Jan" ;; 2 ) month="Feb" ;;
3 ) month="Mar" ;; 4 ) month="Apr" ;;
5 ) month="May" ;; 6 ) month="Jun" ;;
7 ) month="Jul" ;; 8 ) month="Aug" ;;
9 ) month="Sep" ;; 10) month="Oct" ;;
11) month="Nov" ;; 12) month="Dec" ;;
* ) echo "$0: Unknown numeric month value $1" >&2; exit 1
esac
return 0
Collecting stdout with -
echo "Enter something: " | cat -
Formatting Long Lines fmt
Will make lines no longer than 30 characters, not cutting off any words.
fmt -w30 long_text.txt
IFS - Internal Field Seperator
Sets the internal delimiter
ifs_variable.sh
#!/bin/bash
IFS=":"
var='a:b-c~d'
for n in $var
do
echo "$n"
done
Results in
$ ./1/ifs_variable.sh
a
b-c~d
IFS in Great Expectations Action
I’m using this in the Great Expectations Action to parse a list of arguments given as a string to an input
# Loop through checkpoints
STATUS=0
IFS=','
for c in $INPUT_CHECKPOINTS;do
echo ""
echo "Validating Checkpoint: ${c}"
if ! great_expectations checkpoint run $c; then
STATUS=1
fi
done
IFS for iterating through $PATH
#!/bin/bash
IFS=":"
for directory in $PATH ; do
echo $directory
done
IFS: Double vs. Single Quotes
With double quotes the outcome of the command expansion would be fed as one parameter to the source command. Without quotes it would be broken up into multiple parameters, depending on the value of IFS which contains space, TAB and newline by default.
var="some value"
# $var fed into cmd as one parameter
cmd "$var"
# $var is fed into cmd as two parameters
# delimted by the default IFS character, space
cmd '$var'
$RANDOM
echo $RANDOM
will print out a random number
Debugging Shell Scripts -x
Debug a script:
bash -x myscript.sh
OR, within a script:
set -x # start debugging
./myscript.sh
set +x # stop debugging
All variables will be substituted and lines that are run will be printed to screen, showing the control flow of the program
Sourcing files with .
So you can “import” scripts
. myscript.sh
# is equivalent to
source myscript.sh
Using functions to set exit codes
validAlphaNum()
{
# Validate arg: returns 0 if all upper+lower+digits, 1 otherwise.
# Remove all unacceptable chars.
validchars="$(echo $1 | sed -e 's/[^[:alnum:]]//g')"
if [ "$validchars" = "$1" ] ; then
return 0
else
return 1
fi
}
exit validAlphaNum
Know if someone running the script directly with $BASH_SOURCE
The variable $BASH_SOURCE
can let you differentiate between when a script is run standalone vs when its invoked from another script:
if [ "$BASH_SOURCE" = "$0" ]
xargs
https://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct-argument-lists-utility/
> echo 1 2 3 4 | xargs -n2 -I {} echo hello {} world
hello 1 2 world
hello 3 4 world