0

I'm running a find on a directory to do certain operations on files. I also want to count how many files were affected, but some strange things have happened in the loop:

COUNTER=0

find . -type f -name "*.txt" | while read f
do 
  let COUNTER++
  echo Counter is $COUNTER # This shows COUNTER working...
done

echo Counter is $COUNTER # COUNTER is back to 0 at this point...

Why is $COUNTER resetting itself?

Arnab Nandy
  • 6,472
  • 5
  • 44
  • 50
DanDan
  • 10,462
  • 8
  • 53
  • 69
  • 4
    FAQ from [Bash Pitfalls](http://mywiki.wooledge.org/BashPitfalls#grep_foo_bar_.7C_while_read_-r.3B_do_.28.28count.2B-.2B-.29.29.3B_done) also [I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates? Or, why can't I pipe data to read?](http://mywiki.wooledge.org/BashFAQ/024) – kojiro Jan 22 '15 at 13:52
  • @nwinkler While your proposed duplicate got more votes, that question also contains a distracting logic error. There are bound to be dozens of other duplicates to choose from, and mine may not be the best, either. – tripleee Jan 22 '15 at 14:04
  • @tripleee Fair enough, I noticed that the same question had been asked and answered several times, and I picked the one with the most votes :-) – nwinkler Jan 22 '15 at 14:05

3 Answers3

2

Change to:

COUNTER=0

while read -r entry
do 
  let COUNTER++
  echo Counter is $COUNTER # This shows COUNTER working...
done < <(find . -type f -name "*.txt")
arco444
  • 22,002
  • 12
  • 63
  • 67
2

Inside the loop a new SubShell is created, and it has a different context, than the outside world. The already mentioned page summarizes this quite well. The other answer by @arco444 shows the process substitution workaround from this page.

A quote from the page which is relevant to the comments:

BourneShell creates a subshell when the input or output of anything (loops, case etc..) but a simple command is redirected, either by using a pipeline or by a redirection operator ('<', '>').

So the problem is not the loop, but the use of the pipeline (|) operator.

meskobalazs
  • 15,741
  • 2
  • 40
  • 63
  • do you know the reason why `bash` uses SubShell for `while` loop ? – deimus Jan 22 '15 at 14:00
  • I don't exactly know, the page only says *In most shells, each command of a pipeline is executed in a separate SubShell.*. My guess is, that this comes down to the UNIX way of things: a shell is basically interoperating sot of separate programs. – meskobalazs Jan 22 '15 at 14:03
-1

This also works:

COUNTER=0

for line in $(find . -type f -name "*.txt");
do
  let COUNTER++
  echo Counter is $COUNTER
done
Pavel Kucera
  • 124
  • 1
  • 4