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.