0

I wrote a Bash function:

                CAPACITY=0
                USED=0
                FREE=0
                df | grep /$ | while read LINE ; do
                        CAPACITY=$(echo "${CAPACITY}+$(echo ${LINE} | awk '{print $2}')" | bc )
                        USED="$[${USED}+$(echo ${LINE} | awk '{print $3}')]"

                        FREE="$[${FREE}+$(echo ${LINE} | awk '{print $4}')]"
                done

                echo -e "${CAPACITY}\t${USED}\t${FREE}"

                for i in /home /etc /var /usr; do
                        df | grep ${i}[^' ']*$ | while read LINE ; do
                                CAPACITY=$[${CAPACITY}+$(echo ${LINE} | awk '{print $2}')]
                                USED=$[${USED}+$(echo ${LINE} | awk '{print $3}')]
                                FREE=$[${FREE}+$(echo ${LINE} | awk '{print $4}')]
                        done
                done

                if [ "${1}" = "explode?" ] ; then

                        if [ $[${USED}*100/${CAPACITY}] -ge 95 ] ; then
                                return 0
                        else
                                return 1
                        fi
                elif [ "${1}" = "check" ] ; then
                        echo -e "Capacity = $(echo "scale=2; ${CAPACITY}/1024/1024" | bc)GB\nUsed = $(echo "scale=2; ${USED}/1024/1024" | bc)GB\nAvaliable = $(echo "scale=2; ${FREE}/1024/1024" | bc)GB\nUsage = $(echo "scale=2; ${USED}*100/${CAPACITY}" | bc)%"
                fi
}

Note the 2 different methods to store the data in the CAPACITY/USED/FREE vars in the first 'while' loop and the echo right after it to debug the code.

Seems as though while running the script the data inputted into the variables in the loop isn't saved. Here's the output while running the script with 'set -x':

+ CAPACITY=0
+ USED=0
+ FREE=0
+ df
+ grep '/$'
+ read LINE
++ bc
+++ echo /dev/vda1 52417516 8487408 43930108 17% /
+++ awk '{print $2}'
++ echo 0+52417516
+ CAPACITY=52417516
++ echo /dev/vda1 52417516 8487408 43930108 17% /
++ awk '{print $3}'
+ USED=8487408
++ echo /dev/vda1 52417516 8487408 43930108 17% /
++ awk '{print $4}'
+ FREE=43930108
+ read LINE
+ echo -e '0\t0\t0'
0       0       0

Why the heck don't the variables store the new numbers even though it clearly shows a new number was stored?

1 Answer 1

1

Why ... don't the variables store the new numbers even though it clearly shows a new number was stored?

Because the right part of | is run in a subshell, so the changes are not propagated to the parent shell.

$ a=1
$ echo a=$a
a=1
$ true | { a=2; echo a=$a; }
a=2
$ echo a=$a
echo a=1

For more info read bashfaq I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates?. The common solution is to use a process substitution:

while IFS= read -r line; do
    blabla
done < <( blabla )

The $[ is deprecated. Use $((...)) instead. bash hackers wiki obsolete and deprecated syntax.

In bash just use arithmetic expansion (( for numbers comparison. if (( used * 100 / capacity >= 96 )); then.

By convention upper case variables are used for exported variables. Use lower case variable names for script local variables.

The is no need to grep the output of df. Just df /home /etc /var /usr. Or really just read -r capacity used free < <(df /home /etc /var /usr | awk '{ capacity += $1; used += $3; free += $4 } END{print capacity, used, free}').

Sign up to request clarification or add additional context in comments.

2 Comments

In the 'set -x' output you can see the new number set as the variable's value, why isn't it saved?
Literally I answered that. Because it's run in the subshell.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.