Shell Bash script won't send email

Code:
root@Washington:~/bin # bash -version
GNU bash, version 4.3.42(0)-release (amd64-portbld-freebsd10.1)
Copyright.........

Code:
root@Washington:~/bin # uname -K
1001000

The code runs every night without question, the ONLY problem I have is that for some reason the mail won't send.

When I run the line in question (highlighted below) with the variable filled in it runs great. This is after I added the line to
Code:
chmod 774 $lf
.

This is what I run in shell:

Code:
mail -s "Snapshot for XX on Box X" [my email] < /var/log/SNAPSHOTS/[log.file]

I have the entire code below.
Any help would be much appreciated.

PS: I am not a very good coder. I'm sure it's hard to read, but it works. Go easy on my
Code:
root@Washington:~/bin # cat snapshot.sh
#!/usr/local/bin/bash

seed="SNAPSHOTS"                         # Start of it all
bd=/var/$seed                            # Backup Dir - Where the files go
perform_backups="YES"                    # Turns on Backup feature "(YES|NO)"
uid="liberty.roofing"                    # Username SCP uses to log in
rdir="/usr/home/$uid/$seed"              # remote Dir
email="tim.falardeau@gmail.com"          # Where emails go
email_log="YES"                          # Email log feature "(YES|NO)"
rsys="192.168.1.20"                      # System to store files on
rsa="/$uid/.ssh/id_rsa.pub"              # rsa key location
lcopies=7                                # number of local copies to keep
bcopies=30                               # number of copies to keep on backup machine

##############################################
# DO NOT BACKUP DIR YOUR BACKUPS ARE IN !!!! #
##############################################

declare -a files=(/etc/passwd \
/etc/master.passwd \
/root/bin \
/usr/local/etc \
/etc/rc.conf \
/etc/hosts \
/etc/resolv.conf \
/usr/share/skel \
/var/QB \
/var/LibertyRoof)

###############################################################################

numf=${#files[@]}
date=`date +%m-%d-%y`
time=`date '+TIME: %H:%M:%S'`
lf=$bd/snap_$date.log
slf=$bd/snap.log
box=`hostname -s`
tmp=$box"_"$date
tarf="snap_$tmp.tar"
zipf=$bd/$tarf.gz
rzipf=$tarf.gz
filename="$rzipf"



###### BEGIN #######







# Email log file if enabled

sys.summary ()
{
totaldu="$(df -H)"
usrdu="$(du -hs /usr | tail -n1 | cut -f1)"
lrdu="$(du -hs /var/LibertyRoof | tail -n1 | cut -f1)"
sndu="$(du -hs /var/$seed | tail -n1 | cut -f1)"


echo "============================ System Summary ==========================" >> $lf
echo "$totaldu" >> $lf
echo " " >> $lf
echo "Disk Usage broken down by major idex" >> $lf
echo "------------------------------------" >> $lf
echo "/usr uses $usrdu of disk space" >> $lf
echo "/LibertyRoof uses $lrdu of disk space" >> $lf
echo "/var/$seed uses $sndu of disk space" >> $lf
echo "------------------------------------"  >> $lf
echo "Your local dir $bd has $numlc snapshots stored" >> $lf
echo "Your backup system located at $rsys has $numbc stored" >> $lf
echo "======================================================================" >> $lf
}

email.log ()
{
if [[ "$email_log" = "YES" ]]; then
        chmod 774 $lf
        mail -s "Snapshot for $date on $box" $email < $lf
        echo "logfile emailed to $email" >> $slf
else
        echo "### EMAILING OF LOG TURNED OFF ###" >> $slf
fi
}

# Close out log and quit gracefully

quit ()
{
cat $lf >> $slf
sys.summary
email.log
rm $lf
exit
}

# test for and set up Backup Dir

if [ ! -d $bd ]; then
        mkdir $bd
        chmod -R 770 $bd
        chown root:$uid $bd
        echo "--- File created $date $time ---" >> $lf
        touch $bd/starter.file
        (tar -pcf $bd/$tarf $bd/starter.file) &>> $lf
        rm $bd/starter.file
fi
echo "================================================================" >> $lf
echo " Snapshot log entry for $date on machine $box   " >> $lf
echo "================================================================" >> $lf  

# if Directory already has a backup for the day
# rename it. If it already has an ORG file, delete it

if [ -e $zipf ]; then
        if [ -e $zipf.ORG ]; then
                echo "$filename.ORG already exists" >> $lf
                echo "$filename deleted to make room for a new one" >> $lf
                rm $zipf.ORG
        fi
        echo "$filename already exists for date:$date" >> $lf
        echo "$filename renamed $filename.ORG" >> $lf
        mv $zipf $zipf.ORG
fi

echo "Snap shot process started at: $time" >> $lf
echo "Adding files to Tar Backup ($tarf)" >> $lf


# Write array to tape archiver utility
# and preserve permissions

for (( c=0; c<$numf; c++))
do
        wkg_file=${files[$c]}
        if [ -e "$wkg_file" ]; then
                (tar -prf $bd/$tarf $wkg_file) 2>/dev/null
                if [ $? -eq "0" ]; then
                        echo "$wkg_file ---> Successful" >> $lf
                else
                        echo "$wkg_file ---> FAILED" >> $lf
                fi
        fi
done

# Gzip

echo "Compressing Snapshot to $filename" >> $lf

gzip -fq $bd/$tarf
if [[ $? -eq 0 ]]; then
        echo "Compression ---> Succesful" >> $lf
        chown root:$uid $zipf
        chmod 770 $zipf
        if [[ ! -z "$(ls $bd | grep ORG)" ]]; then
                echo "removing obsolete .ORG files" >> $lf
                rm $bd/*.ORG 2>> $lf
        fi
else
        echo "Compression ---> FAILED" >> $lf
        echo "Retaining .ORG files" >> $lf
        echo "Backup NOT Attempted !!" >> $lf
        quit
fi


# Clean and Maintain Local Backup Dir
numlc="$(ls $bd | grep snap | grep -v log | wc -l)"
if [[ "$numlc" -gt "$lcopies" ]]; then
        oldfile="$(ls -tr $bd | grep -v log | head -n1)"
        echo "local copies of backups exceeds $lcopies" >> $lf
        echo "removing $oldfile to maintain sanity" >> $lf
        rm $bd/$oldfile
fi

# Perform Backups to local machine

if [[ "$perform_backups" == "NO" ]]; then
        echo "### Uploads Disabled ###" >> $lf
        echo "============================================" >> $lf
        quit
fi

echo "beginning upload of $filename to $rsys" >> $lf

# Check and/or install remote dir for upload


dirchk="$(su $uid -c "ssh $rsys ls /usr/home/$uid | grep $seed")" 2>> $lf
if [[ -z "$dirchk" ]]; then
        su $uid -c "ssh $rsys mkdir $seed" 2>> $lf
        if [[ $? -ne 0 ]]; then
                echo "couldn't create remote dir $seed...exiting" 2>> $lf
                quit
        fi
        su $uid -c "ssh $rsys chmod 770 $seed" 2>> $lf
fi

file="$(su $uid -c "ssh $rsys ls /usr/home/$uid/$seed | grep $filename")"
if [[ ! -z "$file" ]]; then
        echo "Remote dir already contains $filename" >> $lf
        su $uid -c "ssh $rsys mv $rdir/$filename $rdir/$filename.ORG"
        echo "renamed $filename to $filename.ORG" >> $lf
fi

su $uid -c "scp $zipf $uid@$rsys:$rdir/$rzipf" 2>> $lf

if [[ $? -ne 0 ]]; then
        echo "Upload ---> FAILED" >> $lf
        quit
else
        echo "Upload ---> Succesful" >> $lf
        if [[ ! -z "$(su $uid -c "ssh $rsys ls $rdir | grep ORG")" ]]; then
                echo "removing obsolete .ORG files" >> $lf
                su $uid -c "ssh $rsys rm $rdir/*.ORG" 2>> $lf
        fi
fi

# Cleaning up Backup Server to maintain sanity

numbc="$(su $uid -c "ssh $rsys ls $rdir | grep snap | grep -v log | wc -l")"

if [[ "$numbc" -gt "$bcopies" ]]; then
        oldfile="$(su $uid -c "ssh $rsys ls -Ur $rdir | grep -v log | head -n1")"
        echo "number of backup copies exceeds $bcopies" >> $lf
        echo "removing $oldfile to maintain sanity" >> $lf
        su $uid -c "ssh $rsys rm $rdir/$oldfile" 2>> $lf
        echo "=========================== EOF ============================" >> $lf

fi

quit
 
I don't see anything obviously wrong. As it's common to run scripts through crontab(1) using /path/to/some/script.sh > /dev/null 2>&1 try redirecting the output to a log file instead of /dev/null. That might provide an error message.
 
I added :

Code:
if [ "$1" = "-d ]; then
set -x
fi

this is what I got...

Code:
root@Washington:~/bin # snapshot -d
snapshot: Command not found.
root@Washington:~/bin # snapshot.sh -d
+ '[' '!' -d /var/SNAPSHOTS ']'
+ echo ================================================================
+ echo ' Snapshot log entry for 11-04-15 on machine Washington   '
+ echo ================================================================
+ '[' -e /var/SNAPSHOTS/snap_Washington_11-04-15.tar.gz ']'
+ echo 'Snap shot process started at: TIME: 11:51:04'
+ echo 'Adding files to Tar Backup (snap_Washington_11-04-15.tar)'
+ (( c=0 ))
+ (( c<1 ))
+ wkg_file=/etc/passwd
+ '[' -e /etc/passwd ']'
+ '[' 0 -eq 0 ']'
+ echo '/etc/passwd ---> Successful'
+ (( c++ ))
+ (( c<1 ))
+ echo 'Compressing Snapshot to snap_Washington_11-04-15.tar.gz'
+ gzip -fq /var/SNAPSHOTS/snap_Washington_11-04-15.tar
+ [[ 0 -eq 0 ]]
+ echo 'Compression ---> Succesful'
+ chown root:liberty.roofing /var/SNAPSHOTS/snap_Washington_11-04-15.tar.gz
+ chmod 770 /var/SNAPSHOTS/snap_Washington_11-04-15.tar.gz
++ ls /var/SNAPSHOTS
++ grep ORG
+ [[ ! -z '' ]]
++ ls /var/SNAPSHOTS
++ grep snap
++ grep -v log
++ wc -l
+ numlc='       8'
+ [[        8 -gt 7 ]]
++ ls -tr /var/SNAPSHOTS
++ grep -v log
++ head -n1
+ oldfile=snap_Washington_10-28-15.tar.gz
+ echo 'local copies of backups exceeds 7'
+ echo 'removing snap_Washington_10-28-15.tar.gz to maintain sanity'
+ rm /var/SNAPSHOTS/snap_Washington_10-28-15.tar.gz
+ [[ YES == \N\O ]]
+ echo 'beginning upload of snap_Washington_11-04-15.tar.gz to 192.168.1.20'
++ su liberty.roofing -c 'ssh 192.168.1.20 ls /usr/home/liberty.roofing | grep SNAPSHOTS'
+ dirchk=SNAPSHOTS
+ [[ -z SNAPSHOTS ]]
++ su liberty.roofing -c 'ssh 192.168.1.20 ls /usr/home/liberty.roofing/SNAPSHOTS | grep snap_Washington_11-04-15.tar.gz'
+ file=
+ [[ ! -z '' ]]
+ su liberty.roofing -c 'scp /var/SNAPSHOTS/snap_Washington_11-04-15.tar.gz liberty.roofing@192.168.1.20:/usr/home/liberty.roofing/SNAPSHOTS/snap_Washington_11-04-15.tar.gz'
+ [[ 0 -ne 0 ]]
+ echo 'Upload ---> Succesful'
++ su liberty.roofing -c 'ssh 192.168.1.20 ls /usr/home/liberty.roofing/SNAPSHOTS | grep ORG'
+ [[ ! -z '' ]]
++ su liberty.roofing -c 'ssh 192.168.1.20 ls /usr/home/liberty.roofing/SNAPSHOTS | grep snap | grep -v log | wc -l'
+ numbc='       9'
+ [[        9 -gt 30 ]]
+ quit
+ cat /var/SNAPSHOTS/snap_11-04-15.log
+ sys.summary
++ df -H
+ totaldu='Filesystem      Size    Used   Avail Capacity  Mounted on
/dev/ada0s1a    1.9T    253G    1.5T    14%    /
devfs           1.0k    1.0k      0B   100%    /dev
fdescfs         1.0k    1.0k      0B   100%    /dev/fd'
++ du -hs /usr
++ tail -n1
++ cut -f1
+ usrdu=' 77G'
++ du -hs /var/LibertyRoof
++ tail -n1
++ cut -f1
+ lrdu=' 24G'
++ du -hs /var/SNAPSHOTS
++ tail -n1
++ cut -f1
+ sndu=134G
+ echo '============================ System Summary =========================='
+ echo 'Filesystem      Size    Used   Avail Capacity  Mounted on
/dev/ada0s1a    1.9T    253G    1.5T    14%    /
devfs           1.0k    1.0k      0B   100%    /dev
fdescfs         1.0k    1.0k      0B   100%    /dev/fd'
+ echo ' '
+ echo 'Disk Usage broken down by major idex'
+ echo ------------------------------------
+ echo '/usr uses  77G of disk space'
+ echo '/LibertyRoof uses  24G of disk space'
+ echo '/var/SNAPSHOTS uses 134G of disk space'
+ echo ------------------------------------
+ echo 'Your local dir /var/SNAPSHOTS has        8 snapshots stored'
+ echo 'Your backup system located at 192.168.1.20 has        9 stored'
+ echo ======================================================================
+ email.log
+ [[ YES = \Y\E\S ]]
+ chmod 774 /var/SNAPSHOTS/snap_11-04-15.log
+ mail -s 'Snapshot for 11-04-15 on Washington' tim.falardeau@gmail.com
+ echo 'logfile emailed to tim.falardeau@gmail.com'
+ rm /var/SNAPSHOTS/snap_11-04-15.log
+ exit

It ran fine and sent an email this time! I don't get it. When cron runs it, nothing..
 
I added this to my crontab.
Hopefully it will give me some insight.

Code:
# Nightly Snapshot Backup Script
0       23      *       *       *       root    /root/bin/snapshot.sh -d 2>&1 >/root/snap.output
 
check the order of stderr, stdout redirections. That way, it reads: put 2 where 1 goes, then put 1 to somewhere else. > foo 2>&1 instead when both are to go into foo.

Juha
 
Honestly, you hit on the one aspect of scripting that make me want to drink hot blood and die...
I never understood error/output redirection... I have read the FreeBSD handbook on it many time...
I have some sort of mental starch block...
Is it too much of me to ask just a brief synopsis with example as to how that stuff works again?
I'll understand if you just ignore this...
 
It goes from left to right, in steps. Shell parses one piece, does one redirection at a time. Nothing magic, just rigid simple rules. You could as well say 2> foo 1>&2 which reads put stderr into foo, then put stdout where stderr goes. When you say 2>&1, it does NOT mean that from now on there is only one pipe. There is always two pipes, 1 and 2, but you can move them around one by one, from bucket to another.

Juha
 
The & in >&1 is just part of the notation. A single > just says pipe it to a file, >> pipes the same data to a file but appends it instead of overwriting. The >& is a redirection from one pipe to another. And the numbers are 0 for STDIN, 1 for STDOUT and 2 for STDERR. If there are no numbers it's assumed to be STDOUT or 1.

So
command > /some/file redirects STDOUT to /some/file
command 1> /some/file does the same
command 2> /some/file redirects STDERR to /some/file
command 2> /some/file 1> /some/other/file redirects STDERR to /some/file and STDOUT to /some/other/file
command 2>&1 > /some/file redirects STDERR to STDOUT and STDOUT is redirected to /some/file. Effectively combining the output of STDOUT and STDERR to /some/file.
 
command 2>&1 > /some/file redirects STDERR to STDOUT and STDOUT is redirected to /some/file. Effectively combining the output of STDOUT and STDERR to /some/file.

No no noooo :) Please, the other way around, command > /some/file 2>&1. I have to verify it myself:
Code:
hopo $ sleep abc 2>&1 > foo
usage: sleep seconds

Usage goes into stderr, and stderr was put where stdout was going at that point, into the terminal. Before >foo was parsed.

Juha
 
I believe command 2>&1 > /some/file has been equal to command > /some/file 2>&1 in some shells before because I remember using it that way. Maybe it's just one of those funny bashisms that were fixed later.
 
To be honest I always use the command > /some/file 2>&1 but I swapped them because the "wrong" order was easier to explain. Maybe it's my memory but I can remember a command line is parsed from the end towards the beginning, not as you might expect from the beginning to the end. So for command > /some/file 2>&1 it's the 2>&1 that gets processed first.
 
The & in >&1 is just part of the notation. A single > just says pipe it to a file, >> pipes the same data to a file but appends it instead of overwriting. The >& is a redirection from one pipe to another. And the numbers are 0 for STDIN, 1 for STDOUT and 2 for STDERR. If there are no numbers it's assumed to be STDOUT or 1.

So
command > /some/file redirects STDOUT to /some/file
command 1> /some/file does the same
command 2> /some/file redirects STDERR to /some/file
command 2> /some/file 1> /some/other/file redirects STDERR to /some/file and STDOUT to /some/other/file
command 2>&1 > /some/file redirects STDERR to STDOUT and STDOUT is redirected to /some/file. Effectively combining the output of STDOUT and STDERR to /some/file.
Not to go off topic but I wish you would have made this post a few years ago. I was completely confused with this at the time as well. :D
 
Back
Top