Variables getting reset after the while read loop that reads from a pipeline
initiate () {
read -p "Location(s) to look for .bsp files in? " loc
find $loc -name "*.bsp" | while read
do
if [ -f "$loc.bz2" ]
then
continue
else
filcount=$[$filcount+1]
bzip $loc
fi
if [ "$scan" == "1" ]; then bzipint $loc
fi
echo $filcount #Correct counting
echo $zipcount #Correct counting
echo $scacount #Correct counting
echo $valid #Equal to 1
done
echo $filcount #Reset to 0
echo $zipcount #Reset to 0
echo $scacount #Reset to 0
echo $valid #Still equal to 1
}
I'm writing a bash shell script to use bzip2
to zip up all .bsp
files inside a directory. In this script I have several variables for counting totals (files, successful zips, successful integrity scans), however I seem to have run into a problem.
When find $loc -name "*.bsp"
runs out of files to give the while read
and while read
exits, it zeros out $filcount
, $zipcount
and $scacount
(all of which are changed (increased) inside initiate ()
, bzip ()
(which is called during initiate ()
) or bzipint ()
(which is also called in initiate ()
).
In order to test if it's something to do with variables changing inside initiate ()
or other functions accessed from it, I used echo $valid
, which is defined outside of initiate ()
(like $filcount
, $zipcount
, etc.), but is not changed from another function inside initiate ()
or inside initiate ()
itself.
Interestingly enough, $valid
does not get reset to 0 like the other variables inside initiate.
Can anyone tell me why my variables magically get reset when while read exits?
if you use bash
while read
do
if [ -f "$REPLY.bz2" ]
then
continue
else
filcount=$[$filcount+1]
bzip $REPLY
fi
if [ "$scan" == "1" ]; then bzipint $REPLY
fi
echo $filcount #Correct counting
echo $zipcount #Correct counting
echo $scacount #Correct counting
echo $valid #Equal to 1
done < <(find $loc -name "*.bsp")
I ran into this problem yesterday.
The trouble is that you're doing find $loc -name "*.bsp" | while read
. Because this involves a pipe, the while read
loop can't actually be running in the same bash process as the rest of your script; bash has to spawn off a subprocess so that it can connect the the stdout of find
to the stdin of the while
loop.
This is all very clever, but it means that any variables set in the loop can't be seen after the loop, which totally defeated the whole purpose of the while
loop I was writing.
You can either try to feed input to the loop without using a pipe, or get output from the loop without using variables. I ended up with a horrifying abomination involving both writing to a temporary file AND wrapping the whole loop in $(...)
, like so:
var="$(producer | while read line; do
...
echo "${something}"
done)"
Which got me var set to all the things that had been echoed from the loop. I probably messed up the syntax of that example; I don't have the code I wrote handy at the moment.