dfj328
dfj328

Reputation: 367

What's happening here? Shell programming

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

Answers (2)

glenn jackman
glenn jackman

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

Vaughn Cato
Vaughn Cato

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

Related Questions