I'm writing a script in AIX 5.3 that will loop through the output of a df
and check each volume against another config file. If the volume appears in the config file, it will set a flag which is needed later in the script. If my config file only has a single column and I use a for
loop, this works perfectly. My problem, however, is that if I use a while read
loop to populate more than one variable per line, any variables I set between the while
and the done
are discarded.
For example, assuming the contents of /netapp/conf/ExcludeFile.conf are a bunch of lines containing two fields each:
volName="myVolume"
utilization=70
thresholdFlag=0
grep volName /netapp/conf/ExcludeFile.conf | while read vol threshold; do
if [ $utilization -ge $threshold ] ; then
thresholdFlag=1
fi
done
echo "$thresholdFlag"
In this example, thresholdFlag will always be 0, even if the volume appears in the file and its utilization is greater than the threshold. I could have added an echo "setting thresholdFlag to 1"
in there, see the echo, and it'll still echo a 0 at the end.
Is there a clean way to do this? I think my while loop is being done in a subshell, and changes I make to variables in there are actually being made to local variables that are discarded after the done
.
Zoredache pointed this out to me in chat, and poige mentioned it in his answer: this problem can be solved with a subshell.
When I had to change from a
for
loop that read a single variable from my grep at a time to awhile read var1 var2
loop that allowed me to read in multiple variables, I was able to hang on to temporary variables I manipulated within the while loop by using parentheses to define an explicit subshell. Here's an example:Without the parentheses, you will always echo a sum of 0. With them, you will echo the sum of the first two values in the first matching line of your grep.
Additionally, as Poige points out in another answer, you can use a subshell to populate an in-scope variable like this:
In this case, the value of var that you echo at the end would be the last sum you calculated in your loop, even though sum got destroyed at the end of the subshell.
Two ways at least — return Err code and check it, or wrap your sub-shell code: