Reputation: 367
I have this shell script here and its doing what i want it do. However, when I try to print out the variables at the end, the $file variables appended to either small, medium or large do not show in the std output. What is the shell doing here and what can I do to fix it?
#!/bin/sh
# sorts txt files into small, medium and large
# depending on number of lines
# small <= 10
# medium <= 100
# large > 100
small="Small Files:"
medium="Medium Files:"
large="Large Files:"
for txtFile in *.txt
do
wc -l $txtFile
done |
while read lineCount file
do
if [ $lineCount -lt 10 ]
then
small="$small $file"
elif [ $lineCount -lt 100 ]
then
medium="$medium $file"
else
large="$large $file"
fi
done
echo "$small"
echo "$medium"
echo "$large"
Upvotes: 1
Views: 143
Reputation: 246807
You can also use process substitution, although readability suffers somewhat:
while read lineCount file; do
if [ $lineCount -lt 10 ]; then
small="$small $file"
elif [ $lineCount -lt 100 ]; then
medium="$medium $file"
else
large="$large $file"
fi
done < <(wc -l *txt)
This works because it removes the pipeline and so the while loop is run in the current shell.
Upvotes: 1
Reputation: 64308
When you use a pipeline, the stages of the pipeline are run as separate processes and the variables that are assigned do not propagate back to the main process. You can do it like this instead:
small="Small Files:"
medium="Medium Files:"
large="Large Files:"
for txtFile in *.txt
do
wc -l $txtFile
done | (
while read lineCount file
do
if [ $lineCount -lt 10 ]
then
small="$small $file"
elif [ $lineCount -lt 100 ]
then
medium="$medium $file"
else
large="$large $file"
fi
done
echo "$small"
echo "$medium"
echo "$large"
)
The parentheses cause the while loop and the echo statements to be grouped into a single process, so the variable values are preserved.
You can see this effect in a simpler example:
x=5;echo | x=6;echo $x
will print 5, whereas
x=5;echo | (x=6;echo $x)
will print 6.
Upvotes: 3