Bash Cookbook
# Bash Cookbook
<a href="https://www.packtpub.com/application-development/bash-cookbook?utm_source=github&utm_medium=repository&utm_campaign=9781788629362"><img src="https://d255esdrn735hr.cloudfront.net/sites/default/files/imagecache/ppv4_main_book_cover/B09892.png" alt="Bash Cookbook" height="256px" align="right"></a>
This is the code repository for [Bash Cookbook](https://www.packtpub.com/application-development/bash-cookbook?utm_source=github&utm_medium=repository&utm_campaign=9781788629362), published by Packt.
**Leverage Bash scripting to automate daily tasks and improve productivity**
## What is this book about?
In Linux, one of the most commonly used and most powerful tools is the Bash shell. With its collection of engaging recipes, Bash Cookbook takes you through a series of exercises designed to teach you how to effectively use the Bash shell in order to create and execute your own scripts.
This book covers the following exciting features:
* Understand the basics of Bash shell scripting on a Linux system
* Gain working knowledge of how redirections and pipes interact
* Retrieve and parse input or output of any command
* Automate tasks such as data collection and creating and applying a patch
* Create a script that acts like a program with different features
If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1788629361) today!
<a href="https://www.packtpub.com/?utm_source=github&utm_medium=banner&utm_campaign=GitHubBanner"><img src="https://raw.githubusercontent.com/PacktPublishing/GitHub/master/GitHub.png"
alt="https://www.packtpub.com/" border="5" /></a>
## Instructions and Navigations
All of the code is organized into folders. For example, Chapter02.
The code will look like the following:
```
#!/bin/bash
AGE=17
if [ ${AGE} -lt 18 ]; then
echo "You must be 18 or older to see this movie"
fi
```
**Following is what you need for this book:**
The Bash Cookbook is for you if you are a power user or system administrator involved in writing Bash scripts in order to automate tasks. This book is also ideal if you are interested in learning how to automate complex daily tasks.
With the following software and hardware list you can run all code files present in the book (Chapter 1-8).
### Software and Hardware List
| Chapter | Hardware required | OS required |
| -------- | ------------------------------------| -----------------------------------|
| 1-8 | Atleast 25 GB Free Storage Space, Access to either a DVD or USB flash drive | Linux Ubuntu 16.04 |
### Related products <Other books you may enjoy>
* Mastering Bash [[Packt]](https://www.packtpub.com/networking-and-servers/mastering-bash?utm_source=github&utm_medium=repository&utm_campaign=9781784396879) [[Amazon]](https://www.amazon.com/dp/1784396877)
* Mastering Linux Shell Scripting - Second Edition [[Packt]](https://www.packtpub.com/virtualization-and-cloud/mastering-linux-shell-scripting-second-edition?utm_source=github&utm_medium=repository&utm_campaign=9781788990554) [[Amazon]](https://www.amazon.com/dp/1788990552)
## Get to Know the Authors
**Ron Brash** was the CTO and co-founder of a successful technology consultancy company that provides services in a multitude of domains, but primarily in FOSS and Linux. For over 7 years, he has worked on embedded systems, which provide security and network connectivity in industrial control systems and SCADA networks, all running an optimized embedded Linux. He participates regularly at FOSS and community events, providing feedback and mini-seminars where appropriate. He loves to share knowledge.
**Ganesh Naik** is an author, consultant, and corporate trainer for embedded Android, embedded Linux, IoT, and ML-related product development. He has over 20 years of experience and project accomplishment in IT. He has been a corporate trainer for Indian Space Research Organization, Intel, GE, Samsung, Motorola, Penang Skills Development Center, and various firms in Singapore and India. He has started a company called Levana Technologies, which works with organizations for consulting and training activities.
## Other books by the authors
* [Learning Linux Shell Scripting](https://www.packtpub.com/networking-and-servers/learning-linux-shell-scripting?utm_source=github&utm_medium=repository&utm_campaign=9781785286216)
* [Learning Linux Shell Scripting - Second Edition](https://www.packtpub.com/networking-and-servers/learning-linux-shell-scripting-second-edition?utm_source=github&utm_medium=repository&utm_campaign=9781788993197)
### Suggestions and Feedback
[Click here](https://docs.google.com/forms/d/e/1FAIpQLSdy7dATC6QmEL81FIUuymZ0Wy9vH1jHkvpY57OiMeKGqib_Ow/viewform) if you have any feedback or suggestions.
Chapter 01
01_script.sh
#!/bin/bash
# Pound or hash sign signifies a comment (a line that is not executed)
whoami #Command returning the current username
pwd #Command returning the current working directory on the filesystem
ls # Command returning the results (file listing) of the current working directory
echo “Echo one 1”; echo “Echo two 2” # Notice the semicolon used to delimit multiple commands in the same execution.
-----------------
02_my_first_script.sh
#!/bin/bash
# Echo this is my first comment
echo "Hello world! This is my first Bash script!"
echo -n "I am executing the script with user: "
whoami
echo -n "I am currently running in the directory: "
pwd
exit 0
--------------------
03_example1.sh
#!/bin/bash
PI=3.14
VAR_A=10
VAR_B=$VAR_A
VAR_C=${VAR_B}
echo "Lets print 3 variables:"
echo $VAR_A
echo $VAR_B
echo $VAR_C
echo "We know this will break:"
echo "0. The value of PI is $PIabc" # Breaks - the interpreter thinks we meant variable: "PIabc"
echo "And these will work:"
echo "1. The value of PI is $PI"
echo "2. The value of PI is ${PI}"
echo "3. The value of PI is" $PI
echo "And we can make a new string"
STR_A="Bob"
STR_B="Jane"
echo "${STR_A} + ${STR_B} equals Bob + Jane"
STR_C=${STR_A}" + "${STR_B}
echo "${STR_C} is the same as Bob + Jane too!"
echo "${STR_C} + ${PI}"
exit 0
--------------------------------
04_if.sh
#!/bin/bash
AGE=17
if [ ${AGE} -lt 18 ]; then
echo "You must be 18 or older to see this movie"
fi
--------------------------------------
05_if_else.sh
#!/bin/bash
AGE=9000
if [ ${AGE} -lt 18 ]; then
echo "You must be 18 or older to see this movie"
else
echo "You may see the movie!"
exit 1
fi
echo "This line will never get executed"
-----------------------------
06_if_elif.sh
#!/bin/bash
AGE=21
if [ ${AGE} -lt 18 ]; then
echo "You must be 18 or older to see this movie"
elif [ ${AGE} -eq 21 ]; then
echo "You may see the movie and get popcorn"
else
echo "You may see the movie!"
exit 1
fi
echo "This line might not get executed"
--------------------------------------
07_strings_evaluation.sh
#!/bin/bash
MY_NAME="John"
NAME_1="Bob"
NAME_2="Jane"
NAME_3="Sue"
Name_4="Kate"
if [ "${MY_NAME}" == "Ron" ]; then
echo "Ron is home from vacation"
elif [ "${MY_NAME}" != ${NAME_1}" && "${MY_NAME}" != ${NAME_2}" && "${MY_NAME}" == "John" ]; then
echo "John is home after some unnecessary AND logic"
elif [ "${MY_NAME}" == ${NAME_3}" || "${MY_NAME}" == ${NAME_4}" ]; then
echo "Looks like one of the ladies are home"
else
echo "Who is this stranger?"
fi
-----------------------------------------
08_nested_if.sh
#!/bin/bash
USER_AGE=18
AGE_LIMIT=18
NAME="Bob" # Change to your username if you want to execute the nested logic
HAS_NIGHTMARES="true"
if [ "${USER}" == "${NAME}" ]; then
if [ ${USER_AGE} -ge ${AGE_LIMIT} ]; then
if [ "${HAS_NIGHTMARES}" == "true" ]; then
echo "${USER} gets nightmares, and should not see the movie"
fi
fi
else
echo "Who is this?"
fi
----------------------------------------------
09_if_elif_else.sh
#!/bin/bash
VAR=10
# Multiple IF statements
if [ $VAR -eq 1 ]; then
echo "$VAR"
elif [ $VAR -eq 2]; then
echo "$VAR"
elif [ $VAR -eq 3]; then
echo "$VAR"
# .... to 10
else
echo "I am not looking to match this value"
fi
-----------------------------------------------
10_case.sh
#!/bin/bash
VAR=10 # Edit to 1 or 2 and re-run, after running the script as is.
case $VAR in
1)
echo "1"
;;
2)
echo "2"
;;
*)
echo "What is this var?"
exit 1
esac
---------------------------------------------------
11_for.sh
#!/bin/bash
FILES=( "file1" "file2" "file3" )
for ELEMENT in ${FILES[@]}
do
echo "${ELEMENT}"
done
echo "Echo\'d all the files"
-------------------------------
12_do_while.sh
#!/bin/bash
CTR=1
while [ ${CTR} -lt 9 ]
do
echo "CTR var: ${CTR}"
((CTR++)) # Increment the CTR variable by 1
done
echo "Finished"
---------------------------------
13_until.sh
#!/bin/bash
CTR=1
until [ ${CTR} -gt 9 ]
do
echo "CTR var: ${CTR}"
((CTR++)) # Increment the CTR variable by 1
done
echo "Finished"
---------------------------------------
14_function.sh
#!/bin/bash
FILES=( "file1" "file2" "file3" ) # This is a global variable
function create_file() {
local FNAME="${1}" # First parameter
local PERMISSIONS="${2}" # Second parameter
touch "${FNAME}"
chmod "${PERMISSIONS}" "${FNAME}"
ls -l "${FNAME}"
}
for ELEMENT in ${FILES[@]}
do
create_file "${ELEMENT}" "a+x"
done
echo "Created all the files with a function!"
exit 0
------------------------------------------
15_io_maker.sh
#!/bin/bash
source library.sh # You may need to include the path as it is relative
FNAME="my_test_file.txt"
create_file "${FNAME}"
delete_file "${FNAME}"
exit 0
--------------------------------------
16_library.sh
#!/bin/bash
function create_file() {
local FNAME=$1
touch "${FNAME}"
ls "${FNAME}" # If output doesn't return a value - file is missing
}
function delete_file() {
local FNAME=$1
rm "${FNAME}"
ls "${FNAME}" # If output doesn't return a value - file is missing
}
-------------------------------------------
17_return_codes_101.sh
#!/bin/bash
GLOBAL_RET=255
function my_function_global() {
ls /home/${USER}/.bashrc
GLOBAL_RET=$?
}
function my_function_return() {
ls /home/${USER}/.bashrc
return $?
}
function my_function_str() {
local UNAME=$1
local OUTPUT=""
if [ -e /home/${UNAME}/.bashrc ]; then
OUTPUT='FOUND IT'
else
OUTPUT='NOT FOUND'
fi
echo ${OUTPUT}
}
echo "Current ret: ${GLOBAL_RET}"
my_function_global "${USER}"
echo "Current ret after: ${GLOBAL_RET}"
GLOBAL_RET=255
echo "Current ret: ${GLOBAL_RET}"
my_function_return "${USER}"
GLOBAL_RET=$?
echo "Current ret after: ${GLOBAL_RET}"
# And for giggles, we can pass back output too!
GLOBAL_RET=""
echo "Current ret: ${GLOBAL_RET}"
GLOBAL_RET=$(my_function_str ${USER})
# You could also use GLOBAL_RET=`my_function_str ${USER}`
# Notice the back ticks "`"
echo "Current ret after: $GLOBAL_RET"
exit 0
----------------------------------
18_redirection.sh
#!/bin/sh
# Let's run a command and send all of the output to /dev/null
echo "No output?"
ls ~/fakefile.txt > /dev/null 2>&1
# Retrieve output from a piped command
echo "part 1"
HISTORY_TEXT=`cat ~/.bashrc | grep HIST`
echo "${HISTORY_TEXT}"
# Output the results to history.config
echo "part 2"
echo "${HISTORY_TEXT}" > "history.config"
# Re-direct history.config as input to the cat command
cat < history.config
# Append a string to history.config
echo "MY_VAR=1" >> history.config
echo "part 3 - using Tee"
# Neato.txt will contain the same information as the console
ls -la ~/fakefile.txt ~/ 2>&1 | tee neato.txt
-----------------------------------------
19_flags.sh
#!/bin/bash
HELP_STR="usage: $0 [-h] [-f] [-l] [--firstname[=]<value>] [--lastname[=]<value] [--help]"
# Notice hidden variables and other built-in Bash functionality
optspec=":flh-:"
while getopts "$optspec" optchar; do
case "${optchar}" in
-)
case "${OPTARG}" in
firstname)
val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
FIRSTNAME="${val}"
;;
lastname)
val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
LASTNAME="${val}"
;;
help)
val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
;;
*)
if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
echo "Found an unknown option --${OPTARG}" >&2
fi
;;
esac;;
f)
val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
FIRSTNAME="${val}"
;;
l)
val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
LASTNAME="${val}"
;;
h)
echo "${HELP_STR}" >&2
exit 2
;;
*)
if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
echo "Error parsing short flag: '-${OPTARG}'" >&2
exit 1
fi
;;
esac
done
# Do we have even one argument?
if [ -z "$1" ]; then
echo "${HELP_STR}" >&2
exit 2
fi
# Sanity check for both Firstname and Lastname
if [ -z "${FIRSTNAME}" ] || [ -z "${LASTNAME}" ]; then
echo "Both firstname and lastname are required!"
exit 3
fi
echo "Welcome ${FIRSTNAME} ${LASTNAME}!"
exit 0
Chapter 02
01_search.sh
#!/bin/bash
# Let's find all the files with the string "Packt"
DIRECTORY="www.packtpub.com/"
SEARCH_TERM="Packt"
# Can we use grep?
grep "${SEARCH_TERM}" ~/* > result1.txt 2&> /dev/null
# Recursive check
grep -r "${SEARCH_TERM}" "${DIRECTORY}" > result2.txt
# What if we want to check for multiple terms?
grep -r -e "${SEARCH_TERM}" -e "Publishing" "${DIRECTORY}" > result3.txt
# What about find?
find "${DIRECTORY}" -type f -print | xargs grep "${SEARCH_TERM}" > result4.txt
# What about find and looking for the string inside of a specific type of content?
find "${DIRECTORY}" -type f -name "*.xml" ! -name "*.css" -print | xargs grep "${SEARCH_TERM}" > result5.txt
# Can this also be achieved with wildcards and subshell?
grep "${SEARCH_TERM}" $(ls -R "${DIRECTORY}"*.{html,txt}) > result6.txt
RES=$?
if [ ${RES} -eq 0 ]; then
echo "We found results!"
else
echo "It broke - it shouldn't happen (Packt is everywhere)!"
fi
# Or for bonus points - a personal favorite
history | grep "ls" # This is really handy to find commands you ran yesterday!
# Aaaannnd the lesson is:
echo "We can do a lot with grep!"
exit 0
------------------------------------------
02_test.sh
#!/bin/bash
STR1='123 is a number, ABC is alphabetic & aBC123 is alphanumeric.'
echo "-------------------------------------------------"
# Want to find all of the files beginning with an uppercase character and end with .pdf?
ls * | grep [[:upper:]]*.pdf
echo "-------------------------------------------------"
# Just all of the directories in your current directory?
ls -l [[:upper:]]*
echo "-------------------------------------------------"
# How about all of the files we created with an expansion using the { } brackets?
ls [:lower:].test .
echo "-------------------------------------------------"
# Files with a specific extension OR two?
echo ${STR1} > test.txt
ls *.{test,txt}
echo "-------------------------------------------------"
# How about looking for specific punctuation and output on the same line
echo "${STR1}" | grep -o [[:punct:]] | xargs echo
echo "-------------------------------------------------"
# How about using groups and single character wildcards (only 5 results)
ls | grep -E "([[:upper:]])([[:digit:]])?.test?" | tail -n 5
exit 0
------------------------------------------------
03_mathexp.sh
#!/bin/bash
# Retrieve file system information and remove header
TARBALL="archive.tar.gz"
CURRENT_PART_ALL=$(df --output=size,avail,used /home -B 1M | tail -n1)
# Iterate through and fill array
IFS=' ' read -r -a array <<< $CURRENT_PART_ALL
# Retrieve the size of the contents of the tarball
COMPRESSED_SZ=$(tar tzvf "${TARBALL}" | sed 's/ \+/ /g' | cut -f3 -d' ' | sed '2,$s/^/+ /' | paste -sd' ' | bc)
echo "First inspection - is there enough space?"
if [ ${array[1]} -lt ${COMPRESSED_SZ} ]; then
echo "There is not enough space to decompress the binary"
exit 1
else
echo "Seems we have enough space on first inspection - continuing"
VAR=$((${array[0]} - ${array[2]}))
echo "Space left: ${VAR}"
fi
echo "Safety check - do we have at least double the space?"
CHECK=$((${array[1]}*2))
echo "Double - good question? $CHECK"
# Notice the use of the bc command?
RES=$(echo "$(mhelper "${array[1]}" "/" "2")>0" | bc -l)
if [[ "${RES}" == "1" ]]; then
echo "Sppppppaaaaccee (imagine zombies)"
fi
# We know that this will break! (Bash is driven by integers)
# if [ $(mhelper "${array[2]}" "/" "2") -gt 0 ]; then
#~ echo "Sppppppaaaaccee (imagine zombies) - syntax error"
# fi
# What if we tried this with Bash and a concept again referring to floats
# e.g., 0.5
# It would break
# if [ $((${array[2]} * 0.5 )) -gt 0 ]; then
# echo "Sppppppaaaaccee (imagine zombies) - syntax error"
# fi
# Then untar
tar xzvf ${TARBALL}
RES=$?
if [ ${RES} -ne 0 ]; then
echo "Error decompressing the tarball!"
exit 1
fi
echo "Decompressing tarball complete!"
exit 0
---------------------------------------------
04_script.sh
#!/bin/bash
# Index zero of VARIABLE is the char 'M' & is 14 bytes long
VARIABLE="My test string"
# ${VARIABLE:startingPosition:optionalLength}
echo ${VARIABLE:3:4}
---------------------------------------
05_builtin-str.sh
#!/bin/bash
# Let's play with variable arrays first using Bash's equivalent of substr
STR="1234567890asdfghjkl"
echo "first character ${STR:0:1}"echo "first three characters ${STR:0:3}"
echo "third character onwards ${STR: 3}"echo "forth to sixth character ${STR: 3: 3}"
echo "last character ${STR: -1}"
# Next, can we compare the alphabeticalness of strings?
STR2="abc"STR3="bcd"STR4="Bcd"
if [[ $STR2 < $STR3 ]]; then echo "STR2 is less than STR3"else echo "STR3 is greater than STR2"fi
# Does case have an effect? Yes, b is less than Bif [[ $STR3 < $STR4 ]]; then echo "STR3 is less than STR4"else echo "STR4 is greater than STR3"fi
---------------------------------------
06_builtin-strng.sh
#!/bin/bash
GB_CSV="testdata/garbage.csv"
EM_CSV="testdata/employees.csv"
# Let's strip the garbage out of the last lines in the CSV called garbage.csv
# Notice the forloop; there is a caveat
set IFS=,
set oldIFS = $IFS
readarray -t ARR < ${GB_CSV}
# How many rows do we have?
ARRY_ELEM=${#ARR[@]}
echo "We have ${ARRY_ELEM} rows in ${GB_CSV}"
# Let's strip the garbage - remove spaces
INC=0
for i in "${ARR[@]}"
do
:
res="${i//[^ ]}"
TMP_CNT="${#res}"
while [ ${TMP_CNT} -gt 0 ]; do
i=${i/, /,}
TMP_CNT=$[$TMP_CNT-1]
done
ARR[$INC]=$i
INC=$[$INC+1]
done
# Lets remove the last character from each line
INC=0
for i in "${ARR[@]}"
do
:
ARR[$INC]=${i::-1}
INC=$[$INC+1]
done
# Now, let's turn all of the characters into uppercase!
INC=0
for i in "${ARR[@]}"
do
:
ARR[$INC]=${i^^}
printf "%s" "${ARR[$INC]}"
INC=$[$INC+1]
echo
done
# In employees.csv update the first field to be prepended with a # character
set IFS=,
set oldIFS = $IFS
readarray -t ARR < ${EM_CSV}
# How many rows do we have?
ARRY_ELEM=${#ARR[@]}
echo;echo "We have ${ARRY_ELEM} rows in ${EM_CSV}"
# Let's add a # at the start of each line
INC=0
for i in "${ARR[@]}"
do
:
ARR[$INC]="#${i}"
printf "%s" "${ARR[$INC]}"
INC=$[$INC+1]
echo
done
# Bob had a name change, he wants to go by the name Robert - replace it!
echo
echo "Let's make Bob, Robert!"
INC=0
for i in "${ARR[@]}"
do
:
# We need to iterate through Bobs first
ARR[$INC]=${i/Bob/Robert}
printf "%s" "${ARR[$INC]}"
INC=$[$INC+1]
echo
done
# Can we delete the day of birth column?
# field to remove is 5 (but -4)
echo;echo "Lets remove the column: birthday (1-31)"
INC=0
COLUM_TO_REM=4
for i in "${ARR[@]}"
do
:
# Prepare to also parse the ARR element into another ARR for
# string manipulation
TMP_CNT=0
STR=""
IFS=',' read -ra ELEM_ARR <<< "$i"
for field in "${ELEM_ARR[@]}"; do
# Notice the multiple argument in an if statement
# AND that we catch the start of it once
if [ $TMP_CNT -ne 0 ] && [ $TMP_CNT -ne $COLUM_TO_REM ]; then
STR="${STR},${field}"
elif [ $TMP_CNT -eq 0 ]; then
STR="${STR}${field}"
fi
TMP_CNT=$[$TMP_CNT+1]
done
ARR[$INC]=$STR
echo "${ARR[$INC]}"
INC=$[$INC+1]
done
-------------------------------------
07_some-strs.sh
#!/bin/bash
STR="1234567890asdfghjkl"
echo -n "First character "; sed 's/.//2g' <<< $STR # where N = 2 (N +1)
echo -n "First three characters "; sed 's/.//4g' <<< $STR
echo -n "Third character onwards "; sed -r 's/.{3}//' <<< $STR
echo -n "Forth to sixth character "; sed -r 's/.{3}//;s/.//4g' <<< $STR
echo -n "Last character by itself "; sed 's/.*\(.$\)/\1/' <<< $STR
echo -n "Remove last character only "; sed 's/.$//' <<< $STR
-------------------------------------
08_more-strsng.sh
#!/bin/sh
GB_CSV="testdata/garbage.csv"
EM_CSV="testdata/employees.csv"
# Let's strip the garbage out of the last lines in the CSV called garbage.csv
# Notice the forloop; there is a caveat
set IFS=,
set oldIFS = $IFS
readarray -t ARR < ${GB_CSV}
# How many rows do we have?
ARRY_ELEM=${#ARR[@]}
echo "We have ${ARRY_ELEM} rows in ${GB_CSV}"
# Let's strip the garbage - remove spaces
INC=0
for i in "${ARR[@]}"
do
:
ARR[$INC]=$(echo $i | sed 's/ //g')
echo "${ARR[$INC]}"
INC=$[$INC+1]
done
# Remove the last character and make ALL upper case
INC=0
for i in "${ARR[@]}"
do
:
ARR[$INC]=$(echo $i | sed 's/.$//' | sed -e 's/.*/\U&/' )
echo "${ARR[$INC]}"
INC=$[$INC+1]
done
# Want to add a # at the beginning of each line?
set IFS=,
set oldIFS = $IFS
readarray -t ARR < ${EM_CSV}
INC=0
for i in "${ARR[@]}"
do
:
ARR[$INC]=$(sed -e 's/^/#/' <<< $i )
echo "${ARR[$INC]}"
INC=$[$INC+1]
done
# Sed can also be used on a per file basis too!
# Want to just strip Bob out and change his name to Robert by manipulating
# the file inplace?
sed -i 's/Bob/Robert/' ${EM_CSV}
sed -i 's/^/#/' ${EM_CSV} # In place, instead of on the data in the array
cat ${EM_CSV}
# Now lets remove the birthdate field from the files
# Starts to get more complex, but is done without a loop or using cut
awk 'BEGIN { FS=","; OFS="," } {$5="";gsub(",+",",",$0)}1' OFS=, ${EM_CSV}
-------------------------------------
09_echo-mayhem.sh
#!/bin/bash
# What about echo?
echo -n "Currently we have seen the command \"echo\" used before"
echo " in the previous script"
echo
echo -n "Can we also have \t tabs? \r\n\r\n?"
echo " NO, not yet!"
echo
echo -en "Can we also have \t tabs? \r\n\r\n?"
echo " YES, we can now! enable interpretation of backslash escapes"
echo "We can also have:"
echo -en '\xF0\x9F\x92\x80\n' # We can also use \0NNN for octal instead of \xFF for hexidecimal
echo "Check the man pages for more info ;)"
---------------------------------------------
10_printf-mayhem.sh
#!/bin/bash
export LC_NUMERIC="en_US.UTF-8"
printf "This is the same as echo -e with a new line (\\\n)\n"
DECIMAL=10.0
FLOAT=3.333333
FLOAT2=6.6666 # On purpose two missing values
printf "%s %.2f\n\n" "This is two decimal places: " ${DECIMAL}
printf "shall we align: \n\n %.3f %-.6f\n" ${FLOAT} ${FLOAT2}
printf " %10f %-6f\n" ${FLOAT} ${FLOAT2}
printf " %-10f %-6f\n" ${FLOAT} ${FLOAT2}
# Can we also print other things?
printf '%.0s-' {1..20}; printf "\n"
# How about we print the hex value and a char for each value in a string?
STR="No place like home!"
CNT=$(wc -c <<< $STR})
TMP_CNT=0
printf "Char Hex\n"
while [ ${TMP_CNT} -lt $[${CNT} -1] ]; do
printf "%-5s 0x%-2X\n" "${STR:$TMP_CNT:1}" "'${STR:$TMP_CNT:1}"
TMP_CNT=$[$TMP_CNT+1]
done
----------------------------------------------------
11_hellobonjour.sh
#!/bin/bash
. gettext.sh
function i_have() {
local COUNT=$1
###i18n: Please leave $COUNT as is
echo -e "\n\t" $(eval_ngettext "I have \$COUNT electronic device" "I have \$COUNT electronic devices" $COUNT)
}
echo $(gettext "Hello")
echo
echo $(gettext "What is your name?")
echo
###i18n: Please leave $USER as is
echo -e "\t" $(eval_gettext "My name is \$USER" )
echo
echo $(gettext "Do you have electronics?")
i_have 0
i_have 1
i_have 2
------------------------------------------------
12_translator.sh
#!/bin/bash./hellobonjour.sh
export TEXTDOMAIN="hellobonjour"export TEXTDOMAINDIR=`pwd`/locale
export LANGUAGE=fr./hellobonjour.sh
----------------------------------------------
13_files-extended.sh
#!/bin/bash
FILE_TO_TEST=""
function permissions() {
echo -e "\nWhat are our permissions on this $2?\n"
if [ -r $1 ]; then
echo -e "[R] Read"
fi
if [ -w $1 ]; then
echo -e "[W] Write"
fi
if [ -x $1 ]; then
echo -e "{X] Exec"
fi
}
function file_attributes() {
if [ ! -s $1 ]; then
echo "\"$1\" is empty"
else
FSIZE=$(stat --printf="%s" $1 2> /dev/null)
RES=$?
if [ $RES -eq 1 ]; then
return
else
echo "\"$1\" file size is: ${FSIZE}\""
fi
fi
if [ ! -O $1 ]; then
echo -e "${USER} is not the owner of \"$1\"\n"
fi
if [ ! -G $1 ]; then
echo -e "${USER} is not among the owning group(s) for \"$1\"\n"
fi
permissions $1 "file"
}
function dir_attributes() {
echo -e "Directory \"$1\" has children:\n\n"
ls $1 | xargs -0
permissions $1 "directory"
}
function checkout_file() {
FILE_TO_TEST=""
echo -en "\nWhat is the complete path of the file you want to inspect?\n # "
read FILE_TO_TEST
echo
# First, does it exist?
if [ ! -e ${FILE_TO_TEST} ]; then
echo "Error: \"${FILE_TO_TEST}\" does not exist!"
exit 1
fi
if [ -f ${FILE_TO_TEST} ]; then
file_attributes ${FILE_TO_TEST}
checkout_file
else
dir_attributes ${FILE_TO_TEST}
checkout_file
fi
}
echo "Welcome to the file attributes tester"
echo
echo "To exit, press CTRL + C"
checkout_file
--------------------------------------------
14_data-csv-to-xml.sh
#!/bin/bash
# Import template variables
source xml-parent.tpl
source word.tpl
OUTPUT_FILE="words.xml"
INPUT_FILE="words.csv"
DELIMITER=','
# Setup header
echo ${XML_HDR} > ${OUTPUT_FILE}
echo ${SRT_CONTR} >> ${OUTPUT_FILE}
# Enter content
echo ${ELM} | \
sed '{:q;N;s/\n/\\n/g;t q}'| \
awk \
'{ print "awk \x27 BEGIN{FS=\"'${DELIMITER}'\"}{print "$0"}\x27 '${INPUT_FILE}'"}' | \
sh >> ${OUTPUT_FILE}
# Append trailer
echo ${END_CONTR} >> ${OUTPUT_FILE}
cat ${OUTPUT_FILE}
--------------------------------------------
15_data-xml-to-json.sh
!#/bin/bash
INPUT_FILE"words.xml"
OUTPUT_FILE="words.json"
# Easy one line!
xml2json < ${INPUT_FILE} ${OUTPUT_FILE}
Chapter 03
01_whoami.sh
#!/bin/bash
VAR=$0
echo "I was ran as: $VAR"
------------------------------------------
02_mytree.sh
#!/bin/bash
CURRENT_LVL=0
function tab_creator() {
local X=0
local LVL=$1
local TABS="."
while [ $X -lt $LVL ]
do
# Concatonate strings
TABS="${TABS}${TABS}"
X=$[$X+1]
done
echo -en "$TABS"
}
function recursive_tree() {
local ENTRY=$1
for LEAF in ${ENTRY}/*
do
if [ -d $LEAF ];then
# If LEAF is a directory & not empty
TABS=$(tab_creator $CURRENT_LVL)
printf "%s\_ %s\n" "$TABS" "$LEAF"
CURRENT_LVL=$(( CURRENT_LVL + 1 ))
recursive_tree $LEAF $CURRENT_LVL
CURRENT_LVL=$(( CURRENT_LVL - 1 ))
elif [ -f $LEAF ];then
# Print only the bar and not the backwards slash
# And only if a file
TABS=$(tab_creator $CURRENT_LVL)
printf "%s|_%s\n" "$TABS" "$LEAF"
continue
fi
done
}
PARENTDIR=$1
recursive_tree $PARENTDIR 1
------------------------------------------
03_dsetmkr.sh
$ #!/bin/bash
BDIR="files_galore"
rm -rf ${BDIR}
mkdir -p ${BDIR}
touch $BDIR/file1; echo "1111111111111111111111111111111" >
$BDIR/file1;
touch $BDIR/file2; echo "2222222222222222222222222222222" > $BDIR/file2;
touch $BDIR/file3; echo "3333333333333333333333333333333" > $BDIR/file3;
touch $BDIR/file4; echo "4444444444444444444444444444444" > $BDIR/file4;
touch $BDIR/file5; echo "4444444444444444444444444444444" > $BDIR/file5;
touch $BDIR/sameas5; echo "4444444444444444444444444444444" > $BDIR/sameas5;
touch $BDIR/sameas1; echo "1111111111111111111111111111111" > $BDIR/sameas1;
------------------------------------------
04_file-deduplicator.sh
#!/bin/bash
declare -a FILE_ARRAY=()
function add_file() {
# echo $2 $1
local NUM_OR_ELEMENTS=${#FILE_ARRAY[@]}
FILE_ARRAY[$NUM_OR_ELEMENTS+1]=$1
}
function del_file() {
rm "$1" 2>/dev/null
}
function srch_file() {
local NEW="$1"
local SUM="0"
if [ -f $NEW ] && [ ${#FILE_ARRAY[@]} -eq 0 ]; then
# Edge case - can you guess why?
echo $(sha512sum ${NEW} | awk -F' ' '{print $1}')
return
fi
for ELEMENT in ${FILE_ARRAY[@]}
do
SUM=$(sha512sum ${NEW} | awk -F' ' '{print $1}')
if [ "${SUM}" == "${ELEMENT}" ]; then
# Return 1 if ${NEW} is a know file in the array
return "1"
else
# Continue the loop
continue
fi
done
# Return 2 if ${NEW} is a file && is not found
echo "${SUM}"
}
function begin_search_and_deduplication() {
local DIR_TO_SRCH="$1"
for FILE in ${DIR_TO_SRCH}/*
do
RET=$(srch_file ${FILE})
if [[ "${RET}" == "" ]]; then
del_file $FILE
continue
elif [[ "${RET}" == "0" ]]; then
# Duplicate file - delete
continue
elif [[ "${RET}" == "1" ]]; then
continue
else
# Add file and continue
add_file "${RET}" "${FILE}"
continue
fi
done
}
function dump_array() {
local ARR=$1
local SIZE=${#FILE_ARRAY[@]}
# We start at 1 here because our first element is installed at 1 and not 0
# We leave it as an exercise to the reader
for (( i=1; i <= ${SIZE}; i++ ));
do
echo "#$i " ${FILE_ARRAY[$i]}
done
}
echo "Enter directory name to being searching and deduplicating:"
echo "Press [ENTER] when ready"
echo
read DIR
begin_search_and_deduplication "${DIR}"
dump_array
------------------------------------------
05_file-splitter.sh
--------
#!/bin/bash
FNAME=""
LEN=10
TYPE="line"
OPT_ERROR=0
set -f
function determine_type_of_file() {
local FILE="$1"
file -b "${FILE}" | grep "ASCII text" > /dev/null
RES=$?
if [ $RES -eq 0 ]; then
echo "ASCII file - continuing"
else
echo "Not an ASCII file, perhaps it is Binary?"
fi
}
function write_to_file() {
local B_FNAME="$1"
echo -en "${BUFFER}" > "${B_FNAME}.${F_CNT}"
echo "Wrote buffer to file: ${B_FNAME}.${F_CNT}"
}
function read_and_split_by_line() {
local B_FNAME="$1"
local L_CNT=0
local F_CNT=0
local BUFFER=""
# Read with the -r flag
while IFS= read -r LINE;
do
BUFFER+="${LINE}\n"
L_CNT=$((L_CNT+1))
# Lines are set to 10 by default, but should be set to something more
# efficent for IO
if [ ${L_CNT} -eq ${LEN} ]; then
F_CNT=$((F_CNT+1))
write_to_file "${B_FNAME}" ${F_CNT} "${BUFFER}"
L_CNT=0
BUFFER=""
fi
done < ${B_FNAME}
# If we read everything, we should write what remains in the buffer!
if [ "${BUFFER}" != "" ]; then
F_CNT=$((F_CNT+1))
write_to_file "${B_FNAME}" ${F_CNT} "${BUFFER}"
fi
}
function read_and_write_by_size() {
local B_FNAME="$1"
local L_CNT=0
local F_CNT=0
local BUFFER=""
PAGESIZE=$(getconf PAGESIZE)
# Read with the -n flag
while IFS= read -n ${PAGESIZE} LINE;
do
BUFFER+="${LINE}"
L_CNT=$((L_CNT+1))
# Len should reflect an optimal bloc ksize or something for
# efficient IO
if [ $L_CNT -eq ${LEN} ]; then
F_CNT=$((F_CNT+1))
write_to_file "${B_FNAME}" ${F_CNT} "${BUFFER}"
L_CNT=0
BUFFER=""
fi
done < ${B_FNAME}
# If we read everything, we should write what remains in the buffer!
if [ "${BUFFER}" != "" ]; then
F_CNT=$((F_CNT+1))
write_to_file "${B_FNAME}" ${F_CNT} "${BUFFER}"
fi
}
# Add some extra fun to the script
while getopts ":i:l:t:" opt; do
case $opt in
i)
FNAME="$OPTARG"
if [ ! -e $FNAME ] && [ ! -f $FNAME ]; then
echo "ERROR: Input file parameter does not exit, or is not a file"
OPT_ERROR+=1
fi
;;
t)
TYPE="$OPTARG"
if [[ "${TYPE}" != "line" && "${TYPE}" != "size" ]]; then
echo "ERROR: -t must be set to line or size"
OPT_ERROR+=1
fi
;;
l)
LEN="$OPTARG"
if [ $LEN -le 0 ]; then
echo "ERROR: -l must be greater than 0"
OPT_ERROR+=1
fi
;;
\?)
echo "Invalid option: -$OPTARG" >&2
OPT_ERROR+=1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
OPT_ERROR+=1
;;
esac
done
# A bit more sanity checking before continuing
if [ "${FNAME}" == "" ]; then
echo "ERROR: -i input parameter required; filename "
OPT_ERROR+=1
fi
# Exit if we have any errors, otherwise continue to run the splitting
# functionality :)
if [ ${OPT_ERROR} -ne 0 ]; then
exit 1
fi
# Make sure the file is ASCII text - sanity check
determine_type_of_file "${FNAME}"
# And begin!
if [ "${TYPE}" == "size" ]; then
read_and_write_by_size "${FNAME}"
else
read_and_split_by_line "${FNAME}"
fi
# Done!
exit 0
----------------------------------
06_file-joiner.sh
#!/bin/bash
INAME=""
ONAME=""
FNAME=""
WHERE=""
OPT_ERROR=0
TMPFILE1=$(mktemp)
function determine_type_of_file() {
local FILE="$1"
file -b "${FILE}" | grep "ASCII text" > /dev/null
RES=$?
if [ $RES -eq 0 ]; then
echo "ASCII file - continuing"
else
echo "Not an ASCII file, perhaps it is Binary?"
fi
}
function open_input_and_insert() {
local INPUT="$1"
local N_BLOCK="$2"
local FINAL_OUTPUT="$3"
local PTR=$4
local BUFFER=""
local CTR=0
# If the variable for where is not set, just append it.
if [[ "${PTR}" == "" ]]; then
cat "${INPUT}" "${N_BLOCK}" > "${FINAL_OUTPUT}"
return
fi
while IFS= read LINE
do
if [ ${CTR} == ${PTR} ]; then
cat "${N_BLOCK}" >> ${TMPFILE1}
if [ ${CTR} == 0 ]; then
echo -ne "${LINE}\n" >> ${TMPFILE1}
fi
else
echo -ne "${LINE}\n" >> ${TMPFILE1}
fi
CTR=$((CTR + 1))
done < ${INPUT}
mv ${TMPFILE1} ${FINAL_OUTPUT}
}
# Add some extra fun to the script
while getopts ":i:o:w:f:" opt; do
case $opt in
i)
INAME="$OPTARG"
if [ ! -e $INAME ] && [ ! -f $INAME ]; then
echo "ERROR: Input file parameter does not exit, or is not a file"
OPT_ERROR+=1
fi
;;
o)
ONAME="$OPTARG"
;;
f)
FNAME="$OPTARG"
;;
w)
WHERE="$OPTARG"
if [ "${WHERE}" -lt "0" ]; then
echo "ERROR: -w must be greater than 0"
OPT_ERROR+=1
fi
;;
\?)
echo "Invalid option: -$OPTARG" >&2
OPT_ERROR+=1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
OPT_ERROR+=1
;;
esac
done
# A bit more sanity checking before continuing
if [ "${INAME}" == "" ]; then
echo "ERROR: -i input parameter required; filename "
OPT_ERROR+=1
fi
if [ "${ONAME}" == "" ]; then
echo "ERROR: -o input parameter required; filename "
OPT_ERROR+=1
fi
if [ "${FNAME}" == "" ]; then
echo "ERROR: -f FINAL file parameter required; filename "
OPT_ERROR+=1
fi
# Exit if we have any errors, otherwise continue to run the splitting
# functionality :)
if [ ${OPT_ERROR} -ne 0 ]; then
# Cleanup temporary file
unlink ${TMPFILE1}
exit 1
fi
# Make sure the file is ASCII text - sanity check
determine_type_of_file "${INAME}"
# And begin!
open_input_and_insert "${INAME}" "${ONAME}" "${FNAME}" ${WHERE}
# Done !
exit 0
--------------------------------------------
07_data-maker.sh
#!/bin/bash
N_FILES=3
TYPE=binary
DIRECTORY="qa-data"
NAME="garbage"
EXT=".bin"
UNIT="M"
RANDOM=$$
TMP_FILE="/tmp/tmp.datamaker.sh"
function get_random_number() {
SEED=$(($(date +%s%N)/100000))
RANDOM=$SEED
# Sleep is needed to make sure that the next time rnadom is ran, everything is good.
sleep 3
local STEP=$1
local VARIANCE=$2
local UPPER=$3
local LOWER=$VARIANCE
local ARR;
INC=0
for N in $( seq ${LOWER} ${STEP} ${UPPER} );
do
ARR[$INC]=$N
INC=$(($INC+1))
done
RAND=$[$RANDOM % ${#ARR[@]}]
echo $RAND
}
function create_binary_files(){
EXT=".bin"
local NUM_FILES=$1
local LOWER=$2
local UPPER=$3
local COUNTER=0
while [ $COUNTER -lt ${NUM_FILES} ]; do
R_SIZE=$(get_random_number 1 ${LOWER} ${UPPER})
echo "Creating file... please wait..."
dd if=/dev/zero of="${DIRECTORY}/${NAME}${COUNTER}${EXT}" bs="${R_SIZE}${UNIT}" count=1 2> /dev/null
let COUNTER=COUNTER+1
done
}
function create_text_files() {
EXT=".txt"
local NUM_FILES=$1
local VARIANCE=$2
local MIDDLE=$(($3 / 4))
local UPPER=$3
local LOWER=$(($MIDDLE - $VARIANCE))
if [ $LOWER -lt 0 ]; then
LOWER=$(($LOWER * -1))
LOWER=$(($LOWER + 1))
fi
local TRUE=0
local COUNTER=0
while [ $COUNTER -lt ${NUM_FILES} ]; do
END=$(get_random_number 1 ${VARIANCE} ${UPPER})
START=$(get_random_number 1 ${VARIANCE} ${LOWER})
TRUE=0
while [ $TRUE -eq 0 ]; do
if [ $END -gt $START ]; then
TRUE=1
else
echo "Generating random values... please wait..."
END=$(get_random_number 1 ${VARIANCE} ${UPPER})
continue
fi
done
echo "Creating file... please wait..."
dd if="${TMP_FILE}" of="${DIRECTORY}/${NAME}${COUNTER}${EXT}" seek=${START} bs=1 count=$((${END} -${START})) 2> /dev/null
let COUNTER=COUNTER+1
done
}
# Add some extra fun to the script
OPT_ERROR=0
while getopts ":t:n:l:u:" opt; do
case $opt in
t)
TYPE="$OPTARG"
if [[ "${TYPE}" != "binary" && "${TYPE}" != "text" ]]; then
echo "ERROR: -t must be set to line or size"
OPT_ERROR+=1
fi
;;
n)
N_FILES="$OPTARG"
if [ $N_FILES -le 0 ]; then
echo "ERROR: -l must be greater than 0"
OPT_ERROR+=1
fi
;;
l)
LOWER="$OPTARG"
if [ $LOWER -le 0 ]; then
echo "ERROR: -l must be greater than 0"
OPT_ERROR+=1
fi
;;
u)
UPPER="$OPTARG"
if [ $UPPER -le 0 ]; then
echo "ERROR: -l must be greater than 0"
OPT_ERROR+=1
fi
;;
\?)
echo "Invalid option: -$OPTARG" >&2
OPT_ERROR+=1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
OPT_ERROR+=1
;;
esac
done
# Exit if we have any errors, otherwise continue to run the splitting
# functionality :)
if [ ${OPT_ERROR} -ne 0 ]; then
exit 1
fi
case "$TYPE" in
binary)
create_binary_files $N_FILES $LOWER $UPPER
;;
text)
create_text_files $N_FILES $LOWER $UPPER
;;
:)
echo "Unknown type of operaiton"
;;
esac
echo "DONE!"
exit 0
chapter 04
01_recursive_read_input.sh
#!/bin/bash
function recursive_func() {
echo -n "Press anything to continue loop "
read input recursive_func
}
recursive_funcexit 0
--------------------------------------------
02_loop_for_input.sh
#!/bin/bash
for (( ; ; ))
do
echo "Shall run for ever"
sleep 1
done
exit 0
--------------------------------------------
03_loop_while_input.sh
!/bin/bash
EXIT_PLEASE=0
while : # Notice no conditions?
do
echo "Pres CTRL+C to stop..."
sleep 1
if [ $EXIT_PLEASE != 0 ]; then
break
fi
done
exit 0
--------------------------------------------
04_loop_until_input.sh
#!/bin/bash
EXIT_PLEASE=0
until [ $EXIT_PLEASE != 0 ] # EXIT_PLEASE is set to 0, until will never be satisfied
do
echo "Pres CTRL+C to stop..."
sleep 1
done
exit 0
--------------------------------------------
05_loop_and_print.sh
#!/bin/bash
EXIT_PLEASE=0
INC=0
until [ ${EXIT_PLEASE} != 0 ] # EXIT_PLEASE is set to 0, until will never be satisfied
do
echo "Boo $INC" > /dev/null
INC=$((INC + 1))
sleep 1
done
exit 0
--------------------------------------------
06_bad_input.sh
#!/bin/bash
FILE_NAME=$1
echo $FILE_NAME
ls $FILE_NAME
--------------------------------------------
07_better_input.sh
#!/bin/bash
FILE_NAME=$1
# first, strip underscores
FILE_NAME_CLEAN=${FILE_NAME//_/}
FILE_NAME_CLEAN=$(sed 's/..//g' <<< ${FILE_NAME_CLEAN})
# next, replace spaces with underscores
FILE_NAME_CLEAN=${FILE_NAME_CLEAN// /_}
# now, clean out anything that's not alphanumeric or an underscore
FILE_NAME_CLEAN=${FILE_NAME_CLEAN//[^a-zA-Z0-9_.]/}
# here you should check to see if the file exists before running the command
ls "${FILE_NAME_CLEAN}"
--------------------------------------------
08_validate_email.sh
#!/bin/bash
EMAIL=$1
echo "${EMAIL}" | grep '^[a-zA-Z0-9._]*@[a-zA-Z0-9]*\.[a-zA-Z0-9]*$' >/dev/null
RES=$?
if [ $RES -ne 1 ]; then
echo "${EMAIL} is valid"
else
echo "${EMAIL} is NOT valid"
fi
--------------------------------------------
09_validate_ip.sh
#!/bin/bash
IP_ADDR=$1
IFS=.
if echo "$IP_ADDR" | { read octet1 octet2 octet3 octet4 extra;
[[ "$octet1" == *[[:digit:]]* ]] &&
test "$octet1" -ge 0 && test "$octet1" -le 255 &&
[[ "$octet2" == *[[:digit:]]* ]] &&
test "$octet2" -ge 0 && test "$octet2" -le 255 &&
[[ "$octet3" == *[[:digit:]]* ]] &&
test "$octet3" -ge 0 && test "$octet3" -le 255 &&
[[ "$octet4" == *[[:digit:]]* ]] &&
test "$octet4" -ge 0 && test "$octet4" -le 255 &&
test -z "$extra" 2> /dev/null; }; then
echo "${IP_ADDR} is valid"
else
echo "${IP_ADDR} is NOT valid"
fi
--------------------------------------------
10_select_menu.sh
#!/bin/bash
TITLE="Select file menu"
PROMPT="Pick a task:"
OPTIONS=("list" "delete" "modify" "create")
function list_files() {
PS3="Choose a file from the list or type \"back\" to go back to the main: "
select OPT in *; do
if [[ $REPLY -le ${#OPT[@]} ]]; then
if [[ "$REPLY" == "back" ]]; then
return
fi
echo "$OPT was selected"
else
list_files
fi
done
}
function main_menu() {
echo "${TITLE}"
PS3="${PROMPT} "
select OPT in "${OPTIONS[@]}" "quit"; do
case "$REPLY" in
1 )
# List
list_files
main_menu # Recursive call to regenerate the menu
;;
2 )
echo "not used"
;;
3 )
echo "not used"
;;
4 )
echo "not used"
;;
$(( ${#OPTIONS[@]}+1 )) ) echo "Exiting!"; break;;
*) echo "Invalid option. Try another one.";continue;;
esac
done
}
main_menu # Enter recursive loop
--------------------------------------------
11_mytrap.sh
#!/bin/bash
function setup() {
trap "cleanup" SIGINT SIGTERM
echo "PID of script is $$"
}
function cleanup() {
echo "cleaning up"
exit 1
}
setup
# Loop forever with a noop (:)
while :
do
sleep 1
done
--------------------------------------------
12_mylock.sh
#!/bin.bash
LOCKFILE="/tmp/mylock"
function setup() {
# $$ will provide the process ID
TMPFILE="${LOCKFILE}.$$"
echo "$$" > "${TMPFILE}"
# Now we use hard links for atomic file operations
if ln "${TMPFILE}" "${LOCKFILE}" 2>&- ; then
echo "Created tmp lock"
else
echo "Locked by" $(<$LOCKFILE)
rm "${TMPFILE}"
exit 1
fi
trap "rm ${TMPFILE} ${LOCKFILE}" SIGINT SIGTERM SIGKILL
}
setup
echo "Door was left unlocked"
exit 0
--------------------------------------------
13_mytimeout.sh
#!/bin/bash
SUBPID=0
function func_timer() {
trap "clean_up" SIGALRM
sleep $1& wait
kill -s SIGALRM $$
}
function clean_up() {
trap - ALRM
kill -s SIGALRM $SUBPID
kill $! 2>/dev/null
}
# Call function for timer & notice we record the job's PID
func_timer $1& SUBPID=$!
# Shift the parameters to ignore $0 and $1
shift
# Setup the trap for signals SIGALRM and SIGINT
trap "clean_up" ALRM INT
# Execute the command passed and then wait for a signal
"$@" & wait $!
# kill the running subpid and wait before exit
kill -ALRM $SUBPID
wait $SUBPID
exit 0
--------------------------------------------
14_master.sh
#!/bin/bash
FIFO_FILE=/tmp/WORK_QUEUE_FIFO
mkfifo "${FIFO_FILE}"
NUM_WORKERS=5
I=0
while [ $I -lt $NUM_WORKERS ]; do
bash worker.sh "$I" &
I=$((I+1))
done
I=0
while [ $I -lt $NUM_WORKERS ]; do
echo "$I" > "${FIFO_FILE}"
I=$((I+1))
done
sleep 5
rm -rf "${FIFO_FILE}"
exit 0
--------------------------------------------
15_worker.sh
#!/bin/bash
FIFO_FILE=/tmp/WORK_QUEUE_FIFO
BUFFER=""
echo "WORKER started: $1"
while :
do
read BUFFER < "${FIFO_FILE}"
if [ "${BUFFER}" != "" ]; then
echo "Worker received: $BUFFER"
exit 1
fi
done
exit 0
--------------------------------------------
16_myscript.sh
#!/bin/bash
for (( ; ; ))
do
sleep 1
done
chapter 05
01_server_uptime.sh
serveruptime=`uptime | awk '{print $3,$4}'| sed 's/,//'| grep "day"`;
if [[ -z "$serveruptime" ]]; then
serveruptime=`uptime | awk '{print $3}'| sed 's/,//'`;
echo $serveruptime
else
:;
fi;
--------------------------------------------
02_cpu_info.sh
for cpus in `dmidecode -t4|awk '/Handle / {print $2}'`; do
echo `dmidecode -t4|sed '/Flags/,/Version/d'|egrep -A20 "Handle ${cpus}"|grep -m 1 "Socket Designation"|grep -o '.\{0,0\}:.\{0,18\}'|tr -d '\:| '`;
echo `dmidecode -t4|sed '/Flags/,/Version/d'|egrep -A20 "Handle ${cpus}"|grep -m 1 "Family"|grep -o '.\{0,0\}:.\{0,18\}'|tr -d '\:| '`;
echo `dmidecode -t4|sed '/Flags/,/Version/d'|egrep -A20 "Handle ${cpus}"|grep -m 1 "Manufacturer"|grep -o '.\{0,0\}:.\{0,18\}'|tr -d '\:| '`;
echo `dmidecode -t4|sed '/Flags/,/Version/d'|egrep -A20 "Handle ${cpus}"|grep -m 1 "Current Speed"|grep -o '.\{0,0\}:.\{0,18\}'|tr -d '\:| '`;
echo `dmidecode -t4|sed '/Flags/,/Version/d'|egrep -A20 "Handle ${cpus}"|grep -m 1 "Voltage"|grep -o '.\{0,0\}:.\{0,18\}'|tr -d '\:| '`;
echo `dmidecode -t4|sed '/Flags/,/Version/d'|egrep -A20 "Handle ${cpus}"|grep -m 1 "Core Count"|grep -o '.\{0,0\}:.\{0,18\}'|tr -d '\:| '`;
done
--------------------------------------------
03_test_ipv4.sh
if ping -q -c 1 -W 1 8.8.8.8 >/dev/null; then
echo "IPv4 is up"
else
echo "IPv4 is down"
fi
--------------------------------------------
04_test_ip_dns.sh
if ping -q -c 1 -W 1 google.com >/dev/null; then
echo "The network is up"
else
echo "The network is down"
fi
--------------------------------------------
05_test_web.sh
case "$(curl -s --max-time 2 -I http://google.com | sed 's/^[^ ]* *\([0-9]\).*/\1/; 1q')" in
[23]) echo "HTTP connectivity is up";;
5) echo "The web proxy won't let us through";;
*) echo "The network is down or very slow";;
esac
--------------------------------------------
06_wifi_conn.sh
#!/bin/sh
## usage:
## sudo ./wpa2-wifi-connect.sh <ssid> <pass>
ifdown wlan0
# build the interfaces file that will point to the file that holds our configuration
rm /etc/network/interfaces
touch /etc/network/interfaces
echo 'auto lo' >> /etc/network/interfaces
echo 'iface lo inet loopback' >> /etc/network/interfaces
echo 'iface eth0 inet dhcp' >> /etc/network/interfaces
echo 'allow-hotplug wlan0' >> /etc/network/interfaces
echo 'iface wlan0 inet manual' >> /etc/network/interfaces
echo 'wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf' >> /etc/network/interfaces
echo 'iface default inet dhcp' >> /etc/network/interfaces
# build the supplicant file that holds our configuration
rm /etc/wpa_supplicant/wpa_supplicant.conf
touch /etc/wpa_supplicant/wpa_supplicant.conf
echo 'ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev' >> /etc/wpa_supplicant/wpa_supplicant.conf
echo 'update_config=1' >> /etc/wpa_supplicant/wpa_supplicant.conf
wpa_passphrase $1 $2 >> /etc/wpa_supplicant/wpa_supplicant.conf
ifup wlan0
--------------------------------------------
07_inotify_example.sh
#! /bin/bash
folder=~/Desktop/abc
cdate=$(date +"%Y-%m-%d-%H:%M")
inotifywait -m -q -e create -r --format '%:e %w%f' $folder | while read file
do
mv ~/Desktop/abc/output.txt ~/Desktop/Old_abc/${cdate}-output.txt
done
--------------------------------------------
08_mysql_version.sh
#!/bin/bash
mysql -u root -pTraining2@^ <<MY_QUERY
SELECT VERSION();
MY_QUERY
--------------------------------------------
09_create_database.sh
#!/bin/bash
mysql -u root -pTraining2@^ <<MY_QUERY
create database testdb;
MY_QUERY
--------------------------------------------
10_add_user.sh
#!/bin/bash
#set -x
MY_INPUT='/home/mansijoshi/Desktop'
declare -a A_SURNAME
declare -a A_NAME
declare -a A_USERNAME
declare -a A_DEPARTMENT
declare -a A_PASSWORD
while IFS=, read -r COL1 COL2 COL3 COL4 COL5 TRASH;
do
A_SURNAME+=("$COL1")
A_NAME+=("$COL2")
A_USERNAME+=("$COL3")
A_DEPARTMENT+=("$COL4")
A_PASSWORD+=("$COL5")
done <"$MY_INPUT"
for index in "${!A_USERNAME[@]}"; do
useradd -g "${A_DEPARTMENT[$index]}" -d "/home/${A_USERNAME[$index]}" -s /bin/bash -p "$(echo "${A_PASSWORD[$index]}" | openssl passwd -1 -stdin)"
"${A_USERNAME[$index]}"
done
chapter 06
01_create_alarm.sh
#!/bin/bash
declare -i H
declare -i M
declare -i cur_H
declare -i cur_M
declare -i min_left
declare -i hour_left
echo -e "What time do you Wake Up?"
read H
echo -e "and Minutes?"
read M
cur_H=`date +%H`
cur_M=`date +%M`
echo "You Selected "
echo "$H:$M"
echo -e "\nIt is Currently $cur_H:$cur_M"
if [ $cur_H -lt $H ]; then
hour_left=`expr $H - $cur_H`
echo "$H - $cur_H means You Have: $hour_left hours still"
fi
if [ $cur_H -gt $H ]; then
hour_left=`expr $cur_H - $H`
echo -e "\n$cur_H - $H means you have $hour_left hours left \n"
fi
if [ $cur_H == $H ]; then
hour_left=0
echo -e "Taking a nap?\n"
fi
if [ $cur_M -lt $M ]; then
min_left=`expr $M - $cur_M`
echo -e "$M -$cur_M you have: $min_left minutes still"
fi
if [ $cur_M -gt $M ]; then
min_left=`expr $cur_M - $M`
echo -e "$cur_M - $M you have $min_left minutes left \n"
fi
if [ $cur_M == $M ]; then
min_left=0
echo -e "and no minutes\n"
fi
echo -e "Sleeping for $hour_left hours and $min_left minutes \n"
sleep $hour_left\h
sleep $min_left\m
mplayer ~/.alarm/alarm.mp3
--------------------------------------------
02_yes_no.sh
dialog --yesno "Do you wish to continue?" 0 0
a=$?
if [ "${a}" == "0" ]; then
echo Yes
else
echo No
fi
--------------------------------------------
03_calendar_dialog.sh
dialog --calendar "Select a date... " 0 0 1 1 2018
val=$?
--------------------------------------------
04_checklist_dialog.sh
dialog --stdout --checklist "Enable the account options you want:" 10 40 3 \
1 "Home directory" on \
2 "Signature file" off \
3 "Simple password" off
--------------------------------------------
05_raise_border.sh
convert -raise 5x5 mountain.png mountain-raised.png
--------------------------------------------
06_integrity_check.sh
#!/bin/bash
E_DIR_NOMATCH=50
E_BAD_DBFILE=51
dbfile=Filerec.sha256
# storing records.
set_up_database ()
{
echo ""$directory"" > "$dbfile"
# Write directory name to first line of file.
sha256sum "$directory"/* >> "$dbfile"
# Append sha256 checksums and filenames.
}
check_database ()
{
local n=0
local filename
local checksum
if [ ! -r "$dbfile" ]
then
echo "Unable to read checksum database file!"
exit $E_BAD_DBFILE
fi
while read rec[n]
do
directory_checked="${rec[0]}"
if [ "$directory_checked" != "$directory" ]
then
echo "Directories do not match up!"
# Tried to use file for a different directory.
exit $E_DIR_NOMATCH
fi
if [ "$n" -gt 0 ]
then
filename[n]=$( echo ${rec[$n]} | awk '{ print $2 }' )
# sha256sum writes recs backwards,
#+ checksum first, then filename.
checksum[n]=$( sha256sum "${filename[n]}" )
if [ "${rec[n]}" = "${checksum[n]}" ]
then
echo "${filename[n]} unchanged."
else
echo "${filename[n]} : CHECKSUM ERROR!"
fi
fi
let "n+=1"
done <"$dbfile" # Read from checksum database file.
}
if [ -z "$1" ]
then
directory="$PWD" # If not specified,
else
directory="$1"
fi
clear
if [ ! -r "$dbfile" ]
then
echo "Setting up database file, \""$directory"/"$dbfile"\".";
echo
set_up_database
fi
check_database
echo
exit 0
--------------------------------------------
07_timezones.sh
TZ=":Antarctica/Casey" date
TZ=":Atlantic/Bermuda" date
TZ=":Asia/Calcutta" date
TZ=":Europe/Amsterdam" date
--------------------------------------------
Filerec.md5
/home/student/chapter6
627aba5bbcb3baeb5d2b93c9253366f7 /home/student/chapter6/01_create_alarm.sh
92f6dc226c3cd2b6022dc3ba67a8ddc7 /home/student/chapter6/02_yes_no.sh
0c198b56863bf9803cf6b42dba62a6ea /home/student/chapter6/03_calendar_dialog.sh
c40d3d7f38961ca413de45991816aa76 /home/student/chapter6/04_checklist_dialog.sh
f5c58e4f38384f667456537d63d60f0c /home/student/chapter6/05_raise_border.sh
ad50042115b652d5b258923fbb48ea6e /home/student/chapter6/06_integrity_check.sh
f7b122de4b196b61273d3960d2430085 /home/student/chapter6/07_timezones.sh
f19d1dc2d81a9f174ecfdbd1a75759d4 /home/student/chapter6/1.sh
846b5af8c963284c6099e342fcf74d21 /home/student/chapter6/Filerec.md5
d36b9816e2e23ecd869286d671ea1061 /home/student/chapter6/Filerec.sha256
--------------------------------------------
Filerec.sha256
home/student/chapter6
2eff154a81ce00e9200bd640e4f0d9867a1c93d2506f05c4988b3edf7e5fe989
/home/student/chapter6/01_create_alarm.sh
43fc3c1c02ccf66fcd4f9fc86c1bf030cecbbfe52924d641b0f3da8bf559768e /home/student/chapter6/02_yes_no.sh
502a23a731837c02b6c89ae69433d2de54d047ebd76df4b0331812e5823bff05 /home/student/chapter6/03_calendar_dialog.sh
2e239622ff93691740cd0f89daadc1d9904bcb996d4d3520a658fa4bfb322dde
/home/student/chapter6/04_checklist_dialog.sh
4152530fbeb2705973f53f4e1dce6410b05169c3b1570f1f544eead0a7082e64
/home/student/chapter6/05_raise_border.sh
306de4d77df8f106a6d9f76119196bf0ec7f2901e775e6a40abe3c4a1e016534
/home/student/chapter6/06_integrity_check.sh
3af02d2d2090cc2c95054aa9b5206231b7cff3f9ee0bb9751253cae833336f2f
/home/student/chapter6/07_timezones.sh
07caed801936b890e913c9fbbf052cd7323f3232a1674b2fefe4b0b6994b9939 /home/student/chapter6/Filerec.sha256
chapter 07
--------------------------------------------
01_scrap_contents.sh
$ mkdir -p data
$ cd data
$ wget -q -r -l5 -x 5 https://imdb.com
$ cd ..
$ grep -r -Po -h '(?<=href=")[^"]*' data/ > links.csv
$ grep "^http" links.csv > links_filtered.csv
$ sort -u links_filtered.csv > links_final.csv
$ rm -rf data links.csv links_filtered.csv
--------------------------------------------
02_logging_bot.sh
#!/bin/bash
nick="blb$$"
channel=testchannel
server=irc.freenode.net
config=/tmp/irclog
[ -n "$1" ] && channel=$1
[ -n "$2" ] && server=$2
config="${config}_${channel}"
echo "NICK $nick" > $config
echo "USER $nick +i * :$0" >> $config
echo "JOIN #$channel" >> $config
trap "rm -f $config;exit 0" INT TERM EXIT
tail -f $config | nc $server 6667 | while read MESSAGE
do
case "$MESSAGE" in
PING*) echo "PONG${MESSAGE#PING}" >> $config;; *QUIT*) ;;
*PART*) ;;
*JOIN*) ;;
*NICK*) ;;
*PRIVMSG*) echo "${MESSAGE}" | sed -nr "s/^:([^!]+).*PRIVMSG[^:]+:(.*)/[$(date '+%R')] \1> \2/p";;
*) echo "${MESSAGE}";;
esac
done
--------------------------------------------
03_dmz_iptables.sh
# set the default policy to DROP
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
# to configure the system as a router, enable ip forwarding by
sysctl -w net.ipv4.ip_forward=1
# allow traffic from internal (eth0) to DMZ (eth2)
iptables -t filter -A FORWARD -i eth0 -o eth2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -t filter -A FORWARD -i eth2 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
# allow traffic from internet (ens33) to DMZ (eth2)
iptables -t filter -A FORWARD -i ens33 -o eth2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -t filter -A FORWARD -i eth2 -o ens33 -m state --state ESTABLISHED,RELATED -j ACCEPT
#redirect incoming web requests at ens33 (200.0.0.1) of FIREWALL to web server at 192.168.20.2
iptables -t nat -A PREROUTING -p tcp -i ens33 -d 200.0.0.1 --dport 80 -j DNAT --to-dest 192.168.20.2
iptables -t nat -A PREROUTING -p tcp -i ens33 -d 200.0.0.1 --dport 443 -j DNAT --to-dest 192.168.20.2
#redirect incoming mail (SMTP) requests at ens33 (200.0.0.1) of FIREWALL to Mail server at 192.168.20.3
iptables -t nat -A PREROUTING -p tcp -i ens33 -d 200.0.0.1 --dport 25 -j DNAT --to-dest 192.168.20.3
#redirect incoming DNS requests at ens33 (200.0.0.1) of FIREWALL to DNS server at 192.168.20.4
iptables -t nat -A PREROUTING -p udp -i ens33 -d 200.0.0.1 --dport 53 -j DNAT --to-dest 192.168.20.4
iptables -t nat -A PREROUTING -p tcp -i ens33 -d 200.0.0.1 --dport 53 -j DNAT --to-dest 192.168.20.4
--------------------------------------------
04_incr_backup.sh
#!/bin/bash
gunzip /work/tar.gz
tar uvf /work.tar /work/
gzip /work.tar
chapter 08
01_cal_runtime.sh
clear
ls -l
date
sudo apt install python3
02_if_oneline.sh
a=100
if [ $a -eq 100 ]; then echo "a is equal to $a"; fi
03_for_online.sh
for i in {1..10}; do echo "Hello World"; done
04_while_oneline.sh
x=10
while [ $x -eq 10 ]; do echo $x; sleep 2; done
05_avoid_error.sh
echo "Hello World"
a = 100
b=20
c=$((a+b))
echo $a
06_sample_script.sh
#!/bin/bash
typeset -A config
config=(
[username]="student"
[password]=""
[hostname]="ubuntu"
)
while read line
do
if echo $line | grep -F = &>/dev/null
then
varname=$(echo "$line" | cut -d '=' -f 1)
config[$varname]=$(echo "$line" | cut -d '=' -f 2-)
fi
done < sampleconfig.conf
echo ${config[username]}
echo ${config[password]}
echo ${config[hostname]}
echo ${config[PROMPT_COMMAND]}
07_sampleconfig.conf
password=training
echo rm -rf /
PROMPT_COMMAND='ls -l'
hostname=ubuntu; echo rm -rf /
08_user_wait.sh
#!/bin/bash
time=$(zenity --entry --title="Timer" --text="Enter a duration for the timer.\n\n Use 10s for 10 seconds, 20m for 20 minutes, or 3h for 3 hours.")
sleep $time
zenity --info --title="Timer Complete" --text="The timer is over.\n\n It has been $time."
09_hello.sh
#!/bin/bash
echo "Hello World"
a=10
b=20
c=$((a+b))
echo $c
10_function_example.sh
#!/bin/bash
print_date()
{
echo "Today is `date`"
return
}
print_date
11_function2.sh
#!/bin/bash
display ( ) {
echo 'First Block'
echo 'Number 1'
}
display ( ) {
echo 'Second Block'
echo 'Number 2'
}
display
exit 0