0

while learning bash/ksh from a book. i came across an exercise that had a result i would love to understand.

When executing this script with bash -x to try to understand how it behaves (debugging) i noticed the line variable is number + filename. as this is the result of wc -c [file]. but as soon as the for loop sets the res variable it somehow strips the file name and only says res=23
(number result of wc -c) i can see it happening but don't really understand why ? i think i understand the for loop construct .. for i in xxx do what ever.. don't 100% understand the break in this construct i do know it's to break out of a nested loop.

this is the exercise script:

if [ ! $# -eq 2 ] ;then
    echo
    echo "usage: $0 <location> <FileName>"
    echo
    exit 1
fi
TMPFILE=/tmp/count
line=$(find "$1" -name "$2" -type f -print | tee $TMPFILE | wc -l)
aant=$line
nr=0
som=0

while [ $nr -lt "$aant" ] ; do
    nr=$(( nr +1 ))
    bestand=$(head -$nr $TMPFILE | tail -1)
    echo -n "$bestand"
    line=$(wc -c "$bestand")

    for woord in $line ; do
        res=$woord
        break
    done
    echo "  $res"
    som=$(( som + res ))
done

if [ "$aant" -eq 0 ] ; then
    echo "No files found"
else
    echo
    echo "In totaal $aant files take $som bytes of space"
fi

rm $TMPFILE
exit 0
Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
TuxKey
  • 3

3 Answers3

1

In for word in $line, the contents of the variable line is split to words and then expanded for filename globs (see also these questions). The loop then runs once for each resulting value (or "word"). In this case though, there is only one iteration of the loop at most, since the break statement stops the loop from running. As a result, the value of res set on that first iteration of the loop remains, and the effect is the same as picking the first whitespace-separated word from line.

There would be better ways of writing that, we could e.g. remove the filename with shell expansions. This would output 23:

line='23 somefilename'
res="${line%% *}"
echo "$res"

Or, just have wc not output the filename to begin with, by redirecting the file to wc's stdin, instead of passing the filename to wc. Compare these two:

$ wc -c foo.txt
8 foo.txt
$ wc -c < foo.txt
8
ilkkachu
  • 138,973
  • Thanks for your help. i appreciate it. your explanation was very clear.. running the script in debug mode did show me the break but i did not realize what was really happening.. – TuxKey Apr 18 '19 at 10:58
0

If I understand your question correctly, the magic happens right here:

for woord in $line ; do
    res=$woord
    break
done

To help you understand how that works, maybe considering this will help:

for N in 1 2 3 4 5; do
    echo $N
done
echo "N is $N"

Next, add the "break" statement and consider:

for N in 1 2 3 4 5; do
    echo $N
    break
done
echo "N is $N"

Can you describe what adding the break statement did to the for loop?

In my opinion, the four lines of code I originally quoted could be pared down to just three:

for res in $line ; do
    break
done

This is essentially a "kludgy" way of saying:

res="$(awk '{print $1}' <<< "$line")"
Jim L.
  • 7,997
  • 1
  • 13
  • 27
  • thanks appreciate your help... your little test was a big help to visualize what was happening.. without the break i got a print of each number in a new line 1 true 5.. and on the last line : N is 5. Adding the break i only got 1 and then N is 1. running it with bash -x showed this clearly.. more so then my script.. as i said to "ilkkachu" i did see the break when running it with bash -x .. but did not fully realize what was going on i guess. thanks again. – TuxKey Apr 18 '19 at 11:02
0

Check the man page for wc -c.

It outputs bytecount filename into $line as a space separated list.

The for $woord in $line loop reads the first variable (up till the first space) from $list, which is the bytecount and stores this in $res. Then instead of going on to read the next item in $list it hits the break instruction and exits the loop.

As @ikkachu says, there are easier ways to get the bytecountthan with a loop.

bu5hman
  • 4,756
  • thanks for your help.. i did read the man page.. in fact this little puzzle was bugging me for a while.. and i would never ask anyone for help if i did not put the effort of trying to understand and RTF it first.. even running the script with bash -x showed me what was happening but i did not fully comprehend what i was looking at.. thanks to all you guys i understand what's happening and why. – TuxKey Apr 18 '19 at 11:08