Table of Contents
Bash
Quick guide to shell scripts in BASH
BASH Quotes examples
BASH Get Options
POST to API with cURL
BASH references and shortcuts
BASH Snippets
Ascii Art
What is BASH?
BASH stands for the Bourne Again SHell, which is based on the UNIX C Shell and the Korn Shell. It is POSIX2 compliant.
The shell is the way users or scripts communivate with the Kernel. See https://askubuntu.com/questions/161511/are-the-linux-utilities-parts-of-the-kernel-shell for info on shells and kernels.
Bash Config files
Your home directory will containup to 3 files for configuring BASH, the default system wide file is /etc/profile, but ~/.bash_profile will override this. It is read every time you log in.
~/.bashrc is run each time you start a subshell.
~/.bash_logout is run when a login shell exits.
~/.bash_history is not really a config file, but stores a list of the commands you have run.
Generic script frameworks
Developed over time, these are frameworks which allows me to concentrate on the purpose of the script, the “boilerplate” code is already written and handles the boring stuff such as parsing input, reporting errors and writing log files.
Misc
Print tab character.
tab=$(echo -en “\t”)
bash-3.00$ tab=$(echo -en "\t")
bash-3.00$ echo "test $tab test"
test test
bash-3.00$ echo "test${tab}test"
test test
bash-3.00$ echo "test${tab}${tab}test"
test test
bash-3.00$
Specifying the base of a number
value too great for base probably refers to an arithmetic operation on a single 8 or 9 with a leading 0, ie. 08 or 09. Bash assumes this is an octal number from the leading 0 but 8 & 9 are not legal octal characters.
You can specify the base of a number using base#number, usage is:-
RTTMP7=$((10#$RTTMP6 + 10#$RTTMP4))
Running multiple commands
Join two or more commands together, just run them in turn and don't care if they succeed or fail:-
$ command1 ; command2
Logical AND, first command must succeed or second won't get run:-
$ mkdir newdir && cd newdir
Logical OR, runs second command when 1st fails:-
$ [-d newdir ] || mkdir newdir
Combining them:-
$ [-d newdir ] || mkdir newdir && cd newdir
Comparisons
| Arithmetic Comparisons | |
|---|---|
| -lt | < |
| -gt | > |
| -le | ⇐ |
| -ge | >= |
| -eq | == |
| -ne | != |
| String Comparisons | |
|---|---|
| = | equal |
| != | not equal |
| < | less then |
| > | greater then |
| -n s1 | string s1 is not empty |
| -z s1 | string s1 is empty |
Unlike setting variables where a space round the VARIABLE=value is required, comparison operators NEED a space round the operator, thinking on this, setting a variable and testing it are quite different operations, but the = and == for variable setting and testing numeric equality do superficially look similar.
if elif else
ACTION=${1}
if [ "${ACTION}" = "start" ]; then
echo "Starting Apache instances"
elif [ "${ACTION}" = "stop" ]; then
echo "Stopping Apache instances"
else
echo "No parameter passed, Useage:- startstopapache.sh start|stop"
exit 2
fi
if with multiple conditions
#!/bin/bash
FABRIC=$1
if [ "${FABRIC}" = "" ]
then
echo "You need to provide a Fabric number, either 1 or 2"
exit 1
fi
AND
if [ "${FABRIC}" != "1" ] && [ "${FABRIC}" != "2" ]
then
echo "Fabric values can only be 1 or 2"
fi
OR
if [ ${CPRESULT} != 0 ] || [ ${CPUSERRESULT} != 0 ]
then
THRESHOLD=1
fi
if [ -z "${1}" ] || [ -z "${2}" ];
then
printf "Usage:- assumerole.sh <account> <role to assume> \n"
exit 1
fi
for loop
Specify a range of variables to work with
for i in {1..5}
for VARIABLE in bar boyl gm ppy or for VARIABLE in `cat FILENAME`
do
echo "WebSite is ${VARIABLE}, acton is ${ACTION}"
done
subnets= subnet-02dc9fac8fd877129 subnet-0f8b1423c13b2cd79 subnet-049f0d086b3590d8b
for subnet in ${subnets[@]}
do
echo "creating mount target in " $subnet
done
Exit from loop early
break causes the loop to quit, continue just exits the current iteration of the loop, it will just carry on with the next loop iterator value.
# use for loop read all GC servers
for (( gc=0; gc<${GCLENGTH}; gc++ ));
do
echo "Using >${GLOBALCATALOG[$gc]}<"
echo "==============================="
echo ""
ldapsearch -x -L -h ${GLOBALCATALOG[$gc]} -D "${CN}" -W -b "${SEARCHBASE=}" -s sub proxyAddresses
LDAPSEARCHRESULT=$?
if [ ${LDAPSEARCHRESULT} = 0 ]
then
break
fi
done
while loop
Multiline:-
while [ condition ]
do
{
print "$SOMETHING\n";
}
done
On one line:-
while [ condition ]; do print "$SOMETHING\n"; done
Time duration of operation and record exit status
DURATION=$(time (tar -xvzf ${TARLOCATION}/ww-wiki-backup-${DAY}.tar.gz > /dev/null 2>&1) 2>&1)
TARRESULT=$?
echo "untar result is >${TARRESULT}<, " >> ${TMPLOG}
echo -n "Explode return code is >${TARRESULT}<, it took" >> ${TMPLOG}
echo "${DURATION}" >> ${TMPLOG}
echo "" >> ${TMPLOG}
Remove first or last character from variable
Use # for start of variable or % for the end of the variable.
[ scripts]$ FILE=admin.log.bz2
[ scripts]$ echo $FILE
admin.log.bz2
[ scripts]$ FILE=${FILE%.bz2}
[ scripts]$ echo $FILE
admin.log
Getting web page with wget
Basic use:-
$ wget --user='user' --password='pw' 'http://www.yoursite.com/index.html'
wget with login page and cookie is a two stage process. First, login and retreive cookie, secondly use this cookie to download resource:-
$ wget --save-cookies tmpcookies.txt --post-data 'user=user&password=pw' http://www.yoursite.com/login.html $ wget --load-cookies tmpcookies.txt -p http://www.yoursite.com/protectedcontent.html
curl is somewhat similar:-
$ curl -u 'user:pw' 'http://www.yoursite.com'
Spinner.sh
#/bin/bash # written Andrew Stringer 26/07/2013 #Aimlessly spins round waiting for something function spinner() { local delay=0.75 local spinstr='/-\|' printf "...\n" while [ true ]; do local temp=${spinstr#?} printf "[%c]" "$spinstr" local spinstr=$temp${spinstr%"$temp"} sleep $delay printf "\b\b\b" done } echo "Waiting for 10s." echo "================" spinner & LAST_SPINNER_PID=$! sleep 10 kill ${LAST_SPINNER_PID} echo "" echo "Finished!" echo ""
$ ./spinner.sh Waiting for 10s. ================ ... [-] Finished!
Does directory exist
#!/bin/bash DIR=H if [ -d $DIR ]; then echo "Dir $DIR exists" else mkdir H fi
Copy all files between directories
rsync -av src dest
Arrays or Lists
Bash array example, indices start at zero, so below [1] returns the second element ('example'):-
$ andrewsArray=(test example "three" 4) $ echo ${andrewsArray[1]} $ for i in ${andrewsArray[@]}; do ./pipeline --value $i done $ andrewsArray+=( "newItem1" "newItem2" )
Change user password from shell script
$ echo 'username:new_password' | sudo chpasswd
sed - stream editor
Remove comments starting with # from a file.
sed -e "/^#/d" <filename> > outputfile
-e is the regex expression (tautology noted…), ^ anchors to the start of the line, d deletes what is matched.
Remove last line of file
sed -i '$d' myfile.txt
-i allows sed to edit the file in place.
Testing content of zip file
I just want the files in a zip archive, without the Archive header or testing prefix added to each line.
Also, as I need to compare zip files from a bash zip command and from a python equivalent, I want to sort them so diff can compare:-
$ unzip -t /tmp/boto3_python-1.26.59.zip | more Archive: /tmp/boto3_python-1.26.59.zip testing: __pycache__/ OK testing: bin/ OK testing: boto3/ OK testing: boto3-1.26.59.dist-info/ OK
$ unzip -t boto3_python-1.26.59.zip | sed 's/^ testing: //' | sed '/^Archive:/d' | sort > unzup-python-raw.txt
Default value for variable
read -p "AWS region [default is:- eu-west-2]:-" AWS_REGION
AWS_REGION=${AWS_REGION:-eu-west-2}
Remove and recreate directory
# remove any existing directories if they match the current release.
if [ -d "$LIB_DIR" ]; then rm -rf ${LIB_DIR}; fi
mkdir -p ${LIB_DIR}
This page has been accessed:-
Today: 1
Yesterday: 0
Until now: 468
