views:

87

answers:

6

The following shell scrip will check the disk space and change the variable "diskfull" to 1 if the usage is more than 10% The last echo always shows 0 I tried the global diskfull=1 in the if clause but it did not work. How do I change the variable to 1 if the disk consumed is more than 10%

#!/bin/sh
diskfull=0

ALERT=10
df -HP | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print $5 " " $1 }' | while read output;
do
  #echo $output
  usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1  )
  partition=$(echo $output | awk '{ print $2 }' )
  if [ $usep -ge $ALERT ]; then

diskfull=1
exit
  fi
done

echo $diskfull
A: 

I think you must not be getting to the diskfull=1 line, because if you were, you would get no output at all-- the following exit line would exit the script.

I don't know why this isn't working, but note that awk can handle the rest of the work:

diskfull=$(df -HP | grep -vE '^Filesystem|tmpfs|cdrom' | awk 'BEGIN { x = 0 } { if ($5 + 0 >= '$ALERT') { x = 1 } } END { print x }')

This way you don't need the while loop.

Jason Orendorff
A: 

When using pipes the shell seams to use sub-shells to do the work. As $diskfull is not known to these sub-shells the value is never changed.

See: http://www.nucleardonkey.net/blog/2007/08/variable_scope_in_bash.html

I modified your script as follows. It works for me and should work on your system too.

#!/bin/sh
diskfull=0

ALERT=10
stats=`df -HP | grep -vE '^Filesystem|tmpfs|cdrom|none|udev' | awk '{ print $5 "_" $1 }'`
for output in $stats
do
  usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1  )
  partition=$(echo $output | sed s/.*_// )
  #echo $partition -  $usep
  if [ $usep -le $ALERT ]; then
     diskfull=1
     break
  fi
done
echo $diskfull
alexander.egger
A: 

you can do it this way with gawk(no need to use grep). for alerts you can send email to root.

threshold=10
df -HP | awk -v t="$threshold" -v msg="" 'NR>1 && $5+0 > t{ 
    msg=msg $1" is "$5"\n"
}END{print msg}' | mail root

or check whether there is "msg" or not first

threshold=10
result=$(df -HP | awk -v t="$threshold" -v msg="" 'NR>1 && $5+0 > t{ 
    msg=msg $1" is "$5"\n"
}END{print msg}')
if [ -n "$result" ];then
  echo "Overload"
  echo "$result" | mail root

fi
ghostdog74
A: 

In this line:

usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1  )

it's not necessary to use cut. You can do this:

usep=$(echo $output | awk -F% '{ print $1}' )
Dennis Williamson
using gawk, you can use $5+0 to change the field to integer. The % is "automatically gone". (for lack of better word)
A: 

@OP, use an outer brace or ()

count=0
max=10
diskfull=0
df -HP | { while read disk b c d used e
do    
    if [ "$count" -gt 1 ];then
        used=${used%?}
        if [ "$used" -gt "$max" ];then
            echo "overload: $disk, used: $used%"
            diskfull=1
        fi
    fi
    count=$(( count+1 ))
done 
echo "diskfull: $diskfull" 
}
+1  A: 

This is a side-effect of using while in a pipeline. There are two workarounds:

1) put the while loop and all the variables it uses in a separate scope as demonstrated by levislevis86

some | complicated | pipeline | {
    while read line; do
        foo=$( some calculation )
    done
    do_something_with $foo
}
# $foo not available here

2) if your shell allows it, use process substitution and you can redirect the output of your pipeline to the input of the while loop

while read line; do
    foo=$( some calculation )}
done < <(some | complicated | pipeline)
do_something_with $foo
glenn jackman