1. Tip to get the absolute directory of the shell script
# Add the following three lines to get the name # and absolute directory of your script. # The redirection to /dev/null is needed as sometimes cd returns an output scriptName=$(basename $0) scriptDir=$(dirname $0) scriptDir=$(cd $scriptDir > /dev/null 2>&1; pwd) echo $scriptName echo $scriptDir
2. Using getopt to parse a script command line with options
#!/bin/bash
# Options: getOpt_example [-a | -b ] [-h] [args]
# Examples
# Valid
# ./getOpt_example.sh
# ./getOpt_example.sh -a
# ./getOpt_example.sh -ab abcd
# ./getOpt_example.sh -ab abcd xyz
# ./getOpt_example.sh -ab abcd xyz dddd
# ./getOpt_example.sh xyz dddd -a
# ./getOpt_example.sh xyz dddd -a xyz
# Invalid
# ./getOpt_example.sh -ab
# This is valid, but will yield a wrong result
# (bArg will be "a" and there will be no "-a" option)
# ./getOpt_example.sh -ba xyz
scriptName=$(basename $0)
scriptDir=$(dirname $0)
scriptDir=$(cd $scriptDir > /dev/null 2>&1; pwd)
aOpt=0
bOpt=0
bArg=""
otherArgs=""
parseCmdline()
{
USEROPTS=`getopt -o ab:h -n "$scriptName" -- "$@"`
eval set -- "$USEROPTS"
while [ 1 ]; do
case "$1" in
-a) aOpt=1; shift ;;
-b) bOpt=1; bArg=$2; shift 2 ;;
-h) echo "Display help and exit"; exit ;;
--) shift ; break ;;
*) echo "Display invalid opt error, help and exit"; exit ;;
esac
done
otherArgs=$*
}
parseCmdline $*
echo "aOpt=$aOpt, bOpt=$bOpt bArg=$bArg, otherArgs=$otherArgs"
3. Various ways of getting “dates”
date_today=`date +"%m-%d-%Y"`
printf "\t\tdate_today =\t%s\n" $date_today
date_yesterday=`date -d "1 day ago" +"%m-%d-%Y"`
printf "\tdate_yesterday =\t%s\n" $date_yesterday
date_tomorrow=`date -d "1 day" +"%m-%d-%Y"`
printf "\t\tdate_tomorrow =\t%s\n" $date_tomorrow
date_10_days_from_May1st=`date -d "05/01/2015 + 10 days" +"%m-%d-%Y"`
printf "date_10_days_from_May1st =\t%s\n" $date_10_days_from_May1st
date_1_year_from_today=`date -d "1 year" +"%m-%d-%Y"`
printf "date_1_year_from_today =\t%s\n" $date_1_year_from_today
thismonth=`date +%m`
nextmonth=`expr $thismonth + 1`
useyear=`date +%Y`
if [ $nextmonth -eq 13 ]; then
nextmonth=`expr $nextmonth - 12`
useyear=`$expr $useyear + 1`
fi
date_last_day_of_this_month=`date -d "$nextmonth/1/$useyear 1 day ago" +"%m-%d-%Y"`
printf "date_last_day_of_this_month =\t%s\n" $date_last_day_of_this_month
thismonth=`date +%m`
twomonths=`expr $thismonth + 2`
useyear=`date +%Y`
if [ $twomonths -ge 13 ]; then
twomonths=`expr $twomonths - 12`
useyear=`$expr $useyear + 1`
fi
date_last_day_of_next_month=`date -d "$twomonths/1/$useyear 1 day ago" +"%m-%d-%Y"`
printf "date_last_day_of_next_month =\t%s\n" $date_last_day_of_next_month
thismonth=`date +%m`
useyear=`date +%Y`
date_last_day_of_prev_month=`date -d "$thismonth/1/$useyear 1 day ago" +"%m-%d-%Y"`
printf "date_last_day_of_prev_month =\t%s\n" $date_last_day_of_prev_month
4a. Read one line from a file (option 1)
# Read this script itself
# Any "leading" or "trailing" spaces from every line will be removed
cat $0 | \
while read oneLine; do
echo "|$oneLine|"
done
4b. Read one line from a file (option 2) – a much longer way of doing it, but one I have used a lot, hence adding it here
this_script="$0"
file_len=$(cat $this_script | wc -l)
file_len=$(expr $file_len + 0) # convert to integer
i=1
while [ $i -le $file_len ]; do
one_line=$(head -$i $this_script | tail -1)
echo "|$one_line}"
i=$(expr $i + 1)
done
4c. Read one line from a file (option 3). Using a “bash” specific trick.
this_script="$0"
save_IFS="${IFS}"
IFS=$'\n'
# This for loop will print one line at a time
for one_line in $(cat $this_script)
do
echo "|$one_line|"
done
IFS="${save_IFS}"
# This for loop will revert to the default and print one word at a time
for one_line in $(cat $this_script)
do
echo "|$one_line|"
done
5. Access arrays in scripts
arr[1]="arr1"
arr[2]="arr2"
arr[3]="arr3"
arr[4]="arr4"
arr[5]="arr5"
i=1
while [ $i -le 5 ]; do
echo "${arr[$i]}" # Display an array element
garr[$i]="garr${i}" # Create an array element dynamically
i=`expr $i + 1`
done
i=1
while [ $i -le 5 ]; do
echo "${garr[$i]}" # Display the dynamic array element
i=`expr $i + 1`
done
6a. Age files by deleting files older than “n” days. Option 1 – assuming you have the program “tmpwatch” installed on your machine.
#!/bin/bash
scriptname=`basename $0`
scriptdir=`dirname $0`
scriptdir=`(cd $scriptdir > /dev/null 2>&1; pwd)`
usage()
{
echo "Usage: $scriptname []"
echo ""
echo " BaseDir: All files under this dir will be deleted"
echo " Num Days: Delete files not accessed in Num Days (not created or modified, but accessed)"
echo " Also Delete Dirs and Symlinks: Specify anything as 3rd arg to cause this"
echo ""
echo "Eg.: $scriptname /tmp 10 --- Delete all files under /tmp not accessed in the last 10 days"
echo " $scriptname /tmp 10 dummy --- same as above, but also clean old dirs and symlinks"
}
BaseDir=$1
OlderThanDays=$2
AlsoDeleteDirectories=$3
if [ "x$BaseDir" = "x" ]; then
echo "No base directory specified"
usage
exit 1
fi
if [ "x$OlderThanDays" = "x" ]; then
echo "Specify how many days you want to keep files around"
usage
exit 1
fi
tmpwatch_exe=`which tmpwatch 2> /dev/null`
if [ "x$tmpwatch_exe" = "x" ]; then
tmpwatch_exe=/usr/sbin/tmpwatch
fi
if [ ! -x $tmpwatch_exe ]; then
echo "Unable to find the executable tmpwatch in path or in /usr/sbin"
exit 1
fi
monthDay=`date +"0%0d%^b"`
logfile=/tmp/age_files.log
errfile=/tmp/age_files.err
tmpwatch_options=""
tmpwatch_options="$tmpwatch_options --verbose"
if [ "x$AlsoDeleteDirectories" = "x" ]; then
tmpwatch_options="$tmpwatch_options --nodirs --nosymlinks"
fi
tmpwatch_options="$tmpwatch_options --fuser" # Attempt to use the /sbin/fuser
# to see if a file is already open before
# removing it.
# tmpwatch_options="$tmpwatch_options --test" # Uncomment to just test what will happen
hours=`expr $OlderThanDays \* 24`
echo "$tmpwatch_exe $tmpwatch_options $hours $BaseDir" > $logfile
$tmpwatch_exe $tmpwatch_options $hours $BaseDir 2> $errfile >> $logfile
cat $errfile >> $logfile
6b. Age files by deleting files older than “n” days. Option 2 – Using the traditional “find” method
TBD
7. There have been multiple times when I have had the need to create a “scheduled backup” script on my many UNIX servers. Of course, the goto program to use for the same is rsync, but I have found myself always creating scripts with multiple rsync entries and other variations to skip folders etc. So, I ended creating a “shell include” script which expects certain variables to be defined, and then it would perform the rsync to either a remote server or local server. I have attached a zip file with the .shinc (shell include) and a sample test script.
doRsync.shinc zip file
8.