1

Among other problems with this script I am trying to make (this is the first unix/linux script I have ever made), I am trying to use df to get the % of disk space used and email it to the root. Our instructions were to exclude the /proc floppy and cdrom from df as well.

What I have so far:

fsExclude=(/proc /dev/floppy /dev/cdrom) #Exclusions from df file system
fsUsed=15 #percent to watch for
WarnEmail=root #email for warning message
if (df -x $fsExclude | awk '$5' | sed '2p' > fsUsed)
then
df -h > dfFile.tmp
mail -s "WARNING: Almost out of disk space %" '$WarnEmail' < dfFile.tmp
rm dfFile.tmp
fi

Now I know there is a few things wrong with this. When I run it just to see what kind of output I get, I get (the first line was a message above the if statement I didn't include above ):

Emailing admin, disk almost full...
3 
$WarnEmail... User unknown 
60 
awk:    cmd. line:1: print $4 
awk: cmd. line:1: ^ parse error    
/root/dead.letter... Saved message in /root/dead.letter 
…

There is more but I will save that for later. I have mailed the root outside of the scrip in a similar fashion and had no issues but while in the script it doesn't want to work. With the awk of the df output, I just want to grab the value from that % used column to see if it is greater or less than the fsUsed value. If it is, go in and email the root the entire df output. I have seen while doing some googling that someone suggested using something that had a -perc or -avail but neither worked here. It would tell me that it those were unknown so I tried to go back to awk.

Any help on fixing this would be greatly appreciated.

  • Could you edit and clarify what you need please? Do you want a cumulative percentage? The percentage of each mounted partition? How about unmounted ones? And tmpfs? You are showing an awk error about $4 but your script uses $5. What is fsUsed supposed to do? – terdon Jun 21 '15 at 17:03
  • I want the percent that df outputs in its 5th column to show what % used is. The only ones we were told to exclude were the /proc floppy and cdrom. fsUsed as said above, is the percent to watch for in order to go inside the if statement. So if it hits 15 or more, then go in and mail the root. – Jeremy Jun 21 '15 at 17:16
1

The main issues you have here are

  1. fsExclude is an array, to get all its elements, you need ${array[@]}. In any case, the -x option needs file system types, not devices.

  2. A syntax error in your awk command, you wanted

    awk '{print $5}' 
    

    Without the print, awk will take the expression $5 which evaluates to true if a 5th field exists and will therefore print all lines with at least 5 fields.

  3. If I understand your objective, you seem to want to compare the current percentage with the value of fsUsed. However, your command creates a file called fsUsed and prints the output of df there. What you wanted was

    if [ "$(df -x $fsExclude | awk '$5' | sed '2p')" -gt "$fsUsed" ]
    

    The $() is called command substitution and is expanded to the output of whatever command you ran. That's what you want to compare with the value of fsUsed and to get that value, you need the $.

  4. You have $WarnEMail in single quotes, this means that it is being treated as a string literal and not a variable. Try this instead:

    mail -s "WARNING: Almost out of disk space %" "$WarnEmail" < dfFile.tmp
    
  5. Your df command will return multiple lines, yet you are running a single comparison, that won't work. You will need to check each line of df's output:

Then, you are also doing this in a needlessly complex way. Why not something like this:

#!/bin/bash
fsExclude="/proc|/dev/floppy|/dev/cdrom" #Exclusions from df file system
fsUsed=15 #percent to watch for
WarnEmail=root #email for warning message
problem=0;
df | grep -v "$fsExclude" |
    while read line
    do
    ## Check the percentage, send the mail if at least
    ## one mount point's percentage is > $fsUsed
    if [[ $(grep -oE '[0-9]+%' <<<"$line" | tr -d '%') -gt $fsUsed ]]
    then
        ## I'm not sure if `command | mail` works and I don't have a system
        ## I can test it on. If it doesn't, use a file as you did before. 
        df -h | mail -s "WARNING: Almost out of disk space %" "$WarnEmail" 
        ## No need to rpocess any more lines, exit the while loop
        break;
    fi
    done
  • Thank you very much! Also, thank you for explaining each piece, that helps tremendously. I will give it a shot and see how it works. – Jeremy Jun 21 '15 at 17:42
  • It works! Thank you so much! Such little things to throw it off. – Jeremy Jun 21 '15 at 17:47
0

The showstoppers:

  • You're running the command df -x /proc /dev/floppy /dev/cdrom. This tells df to skip filesystems of type /proc, which don't exist (the filesystem type would be proc), and to list only /dev/floppy and /dev/cdrom. There's no option to omit specific devices, you can filter them out instead.

  • To print the 5th field in awk, use awk '{print $5}': this executes the instruction print $5 on every line. awk '$5' prints the whole line if the fifth field is not zero or empty ($5 is a condition; since there is no corresponding action, the default action is executed, and that prints the whole line). awk 'print $5' is a syntax error.

  • In sed '2p' > fsUsed, the > sign is a redirection operator: the output from the sed command is written to a temporary file fsUsed.

  • '$WarnEmail' is a literal string, consisting of 10 characters starting with a dollar sign. To expand the variable reference, use double quotes.

Also:

  • Don't use a temporary file to store some small output. Use command substitution to put it into a variable.

  • Pass the -P option to df when you're parsing its output. Otherwise it may add newlines in the middle of a record when the device path is too long.

  • You can do all your filtering in awk.

Here's another way to write your script that amalgamates the emails into one.

body=$(df -P | awk -v fsUsed=15 fsExclude='/dev/floppy /dev/cdrom' '
    BEGIN {split(fsExclude, fsExcludeArray)}
    NR == 1 {next}           # skip the header line
    $1 in fsExcludeArray {next}
    {$5 = sub(/%/, "")}      # remove the % character from the Use% column
    $5 > fsUsed {print}      # print lines with almost-full disks
')
if [ -n "$body" ]; then
  # $body is non-empty: there is at least one almost-full filesystem
  echo "$body" | mail -s "Warning: some filesystems are almost full" "$WarnEmail"
fi

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.