LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   bash script does not enter loop (https://www.linuxquestions.org/questions/linux-newbie-8/bash-script-does-not-enter-loop-4175419123/)

bluethundr 07-28-2012 04:57 PM

bash script does not enter loop
 
Hello

I am attempting a bash script that checks disk space on a host. What I'd like to be able to do is to iterate through a list of disks and report on the space free of the disks in the list.

Here is what I was able to come up with:

Code:

#!/bin/bash
volume1='/disk0'
volume2='/global/disk01_01'
volume3='/global/disk02_01'
volume4='/global/backup'
critspace=20
warnspace=40
critpercent=95
warnpercent=90

for i in $volume{1..4}
do

echo $i



    spacefree=$(df -h $i | awk '{print $4}' | grep -v avail | sed 's/G//')
    echo "spacefree $spacefree"
    percentcapacity=$(df -h $i | awk '{print $5}' | grep -v capacity | sed 's/%//')
    echo "percentfree $percentcapacity"

    if [ $spacefree -le $critspace ] && [ $percentcapacity -ge $critpercent  ]; then
      echo "NOK $spacefree free and $percentcapacity user on $i"
      exit 2

    elif [ $spacefree -le $warnspace  ] && [ $percentcapacity -ge $warnpercent  ]; then
      echo "WARNING $spacefree free and $percentcapacity user on $i"
      exit 1

    else
      echo "ALL OK"
      exit 0


fi


done

And this is the output from the script:
Code:

[db-host:root:~]#./check_ora_filesys.sh
/disk0
spacefree 23
percentfree 47
ALL OK

For some reason the code is not looping through the list of volumes as I'd hoped.

I notice that if I move the placement of the 'done' statement to terminate the loop before the code I'm hoping to execute, the looping succeeds.


Code:

#!/bin/bash
volume1='/disk0'
volume2='/global/disk01_01'
volume3='/global/disk02_01'
volume4='/global/backup'
critspace=20
warnspace=40
critpercent=95
warnpercent=90

for i in $volume{1..4}
do

echo $i


done

    spacefree=$(df -h $i | awk '{print $4}' | grep -v avail | sed 's/G//')
    echo "spacefree $spacefree"
    percentcapacity=$(df -h $i | awk '{print $5}' | grep -v capacity | sed 's/%//')
    echo "percentfree $percentcapacity"

    if [ $spacefree -le $critspace ] && [ $percentcapacity -ge $critpercent  ]; then
      echo "NOK $spacefree free and $percentcapacity user on $i"
      exit 2

    elif [ $spacefree -le $warnspace  ] && [ $percentcapacity -ge $warnpercent  ]; then
      echo "WARNING $spacefree free and $percentcapacity user on $i"
      exit 1

    else
      echo "ALL OK"
      exit 0


fi


This is the output if I perform this test

Code:

[db-host:root:~]#./check_ora_filesys.sh
/disk0
/global/disk01_01
/global/disk02_01
/global/backup
spacefree 117
percentfree 21
ALL OK

Thanks, and I'd appreciate any input you may have on this.

pixellany 07-28-2012 07:40 PM

Quick guess: Those "exit" commands are taking you out of the for loop. Check the syntax and usage for "exit".

etech3 07-28-2012 08:42 PM

You may want to try only one disk at a time for now.

Try replacing your exit with
Code:

echo $?
at each stage. If everything is good you should get a 0 on the screen.

If not, it will tell you at what step the error is.

Good Luck ! :D

David the H. 07-29-2012 06:31 AM

Yes, the exit commands will break the script at that point, as long as the conditions match.

Probably the best you can do is save a "status" variable and exit with that at the end. It will only show the status of the last loop iteration though, unless you write something that stores and prints the outputs of all the drives individually.


I would also change the script to use a single array instead of a brace expansion. Much cleaner. It would also be more efficient to store the output of df once, and parse that for the values you want. You can then use parameter substitutions to extract them more efficiently than with awk/sed/grep. The fewer calls to external tools the better, usually.

Finally, when using bash or ksh, it's recommended to use [[..]] for string/file tests, and ((..)) for numerical tests. Avoid using the old [..] test unless you specifically need POSIX-style portability.

http://mywiki.wooledge.org/ArithmeticExpression
http://mywiki.wooledge.org/BashFAQ/031
http://wiki.bash-hackers.org/commands/classictest
http://wiki.bash-hackers.org/syntax/...nal_expression


Here's the modified version I came up with:

Code:

#!/bin/bash

volumes=( '/disk0' '/global/disk01_01' '/global/disk02_01' '/global/backup' )

critspace=20
warnspace=40
critpercent=95
warnpercent=90

for i in ${volumes[@]}"; do

        echo "Processing drive $i"

        #store the output of df in an array
        dfoutput=( $( df -h "$i" | cut -d $'\n' -f2 ) )

        #extract and format the desired fields and echo the results
        spacefree=${dfoutput[3]%G}
        percentcapacity=${dfoutput[4]%\%}

        echo "spacefree $spacefree"
        echo "percentfree $percentcapacity"

        #compare current stats to critical values

        if (( spacefree <= critspace && percentcapacity >= critpercent )); then

                echo "NOK $spacefree free and $percentcapacity user on $i"
                status=2     

        elif (( spacefree <= warnspace && percentcapacity >= warnpercent )); then

                echo "WARNING $spacefree free and $percentcapacity user on $i"
                status=2

        else

                echo "ALL OK"

        fi

done

exit "${status:-0}"

Note that this simply sets the script's exit status to "2" if any of the devices turn up with warnings, which is what I imagine you'd want to happen. Again, more detailed error messages would require extra work.

Notice also how I stored the output of df into an array too (after using cut to chop off the first line), making it easier to access the individual fields.

Actually we could probably even skip using cut and just change it to extract fields 10 and 11 instead.


All times are GMT -5. The time now is 05:11 PM.