GBT55
GBT55

Reputation: 85

How to exit a bash loop and stop the script but only when all the iterations are completed

I have this code, which basically does a loop inside the DF command to see which disks are more than 90% full.

df -H | sed 1d  | awk '{ print $5 " " $1 }' | while read -r dfh; 
do 
    #echo "$output" 
    op=$(echo "$dfh" | awk '{ print $1}' | cut -d'%' -f1 ) 
    partition=$(echo "$dfh" | awk '{ print $2 }' ) 
    if [ $op -ge 90 ];  
    then 
        echo ">> ### WARNING! Running out of space on \"$partition ($op%)\" on $(hostname) as on $(date)" >> LOGFILE 
        echo -e ">> ### WARNING! Running out of space on \"$partition ($op%)\" on $(hostname) as on $(date)" 
        echo ">> There is not enough left storage in the disk to perform the upgrade, exiting..." >> LOGFILE 
        echo -e ">> There is not enough left storage in the disk to perform the upgrade, exiting..." 
        exit 1 
    elif [ $op -ge 85 ]; 
    then 
        echo -e ">> ### WARNING! Running out of space on \"$partition ($op%)\" on $(hostname) as on $(date)" >> LOGFILE 
        echo ">> ### WARNING! Running out of space on \"$partition ($op%)\" on $(hostname) as on $(date)" 
        echo ">> There enough left storage in the disk to perform the upgrade, but it is recommended to first increase the size of the disk $partition" >> LOGFILE 
        echo -e ">> There enough left storage in the disk to perform the upgrade, but it is recommended to first increase the size of the disk $partition"  
    fi 
done 
if [ "$?" -eq 1 ]; 
then 
    exit 
else 
    echo -e ">> There is enough left storage in the disk to continue with the upgrade, OK" 
fi

I want it to exit only if at least one disk is more than 90% full, that's the pourpose of the last if statement

The problem here is that the loop exits on the first disk recognised at more than 90%, this is bad because if I have 3 disks at more than 90% it will only report one of them (the first one in the loop) and then exit. Basically I want the script to report all the disks that are at 90% or more (and the ones that are at 85% too but without exiting, as you can read).

Is this possible? Thank you in advance

Upvotes: 0

Views: 144

Answers (3)

William Pursell
William Pursell

Reputation: 212178

You could do something like:

#!/bin/sh

warn=${1-85}
fail=${2-90}

test "$warn" -lt "$fail" || { echo Invalid parameters >&2; exit 1; }

check_disk(){
    op=${1%%%}
    partition=${2}
    if test "$op" -ge "$warn"; then
        tee -a LOGFILE <<-EOF
            >> ### WARNING! Running out of space on "$partition ($op%)" on $(hostname) as on $(date)
            >> There is not enough left storage in the disk to perform the upgrade, exiting...
        EOF
    fi
    if test "$op" -ge "$fail"; then
        return 1
    fi
} 2> /dev/null

rv=0
df -H | awk 'NR > 1{ print $5 " " $1 }' \
| { while read -r op partition; do
    if ! check_disk "$op" "$partition"; then rv=1; fi
done
test "$rv" -eq 0
} || exit 1

A few notes:

You must have literal hard tabs as indentation if you want the <<- to suppress the indentation in the output.

You need to put the while/done in the brackets to give the rv variable the full scope to be able to check it. If you just do df ... | while do/done, then the variable will be unset outside of the pipeline.

This is still a bit kludgy, and it would probably be better to do the whole thing in awk instead of having the while/do loop in the shell at all, but these are some ideas. In particular, you definitely do not want to be writing the same echo line 4 times!

Also note that parsing the output of df is really fragile. On my box, there are lines in which the filesystem column contains whitespace, so that the 5th column is not the current usage of the mountpoint. This script will probably not work as desired on such output.

Upvotes: 2

tripleee
tripleee

Reputation: 189317

Your script looks like it's screaming loudly to be refactored into Awk. But here is a more gentle refactoring.

rc=0
df -H |
awk 'NR>1 { n=$5; sub(/%/, "", n); print n, $1 }' |
while read -r op partition; 
do 
    if [ $op -ge 90 ];  
    then 
        tee -a LOGFILE <<-________EOF
    >> ### WARNING! Running out of space on "$partition ($op%)" on $(hostname) as on $(date)
    >> There is not enough left storage in the disk to perform the upgrade, exiting...
________EOF
        rc=1
    elif [ $op -ge 85 ]; 
    then
        tee -a LOGFILE <<-________EOF
    >> ### WARNING! Running out of space on "$partition ($op%)" on $(hostname) as on $(date)
    >> There enough left storage in the disk to perform the upgrade, but it is recommended to first increase the size of the disk $partition
________EOF
    fi
    [ "$rc" -eq 0 ]
done &&
echo ">> There is enough left storage in the disk to continue with the upgrade, OK" ||
exit 1

This keeps track of rc while looping over all the partitions, then proceeds with the final condition only when the loop is done.

Generally, avoid echo -e in favor of printf, though here, since the -e wasn't doing anything useful anyway, a here document worked better.

Upvotes: 2

Ivan
Ivan

Reputation: 7253

You can do it in one check, like this:

$ a=10 b=5  c=7 ; (( a>=10 && b>=10 && c>=10 )) && echo 'all >= 10'
$ a=10 b=5  c=10; (( a>=10 && b>=10 && c>=10 )) && echo 'all >= 10'
$ a=10 b=10 c=10; (( a>=10 && b>=10 && c>=10 )) && echo 'all >= 10'
all >= 10

Upvotes: 0

Related Questions