63

I have a script that process a folder, and count the files in the mean time.

i=1
find tmp -type f | while read x
do 
   i=$(($i + 1))
   echo $i
done
echo $i

However, $i is always 1, how do I resolve this?

daisy
  • 54,555

2 Answers2

79

In your example the while-loop is executed in a subshell, so changes to the variable inside the while-loop won't affect the external variable. This is because you're using the loop with a pipe, which automatically causes it to run in a subshell.

Here is an alternative solution using a while loop:

i=1
while read x; do
   i=$(($i + 1))
   echo $i
done <<<$(find tmp -type f)
echo $i

And here is the same approach using a for-loop:

i=1
for x in $(find tmp -type f);
do 
   i=$(($i + 1))
   echo $i
done
echo $i

For more information see the following posts:

Also look at the following chapter from the Advanced Bash Scripting Guide:

igal
  • 9,886
  • 2
    regarding the first solution, isn't it process substitution like so < <(find ...) instead of like so <<<(find ...) .... yours is the latter and that seems incorrect. – Alexander Mills Jun 22 '18 at 03:47
  • @AlexanderMills The <<< operator is called a here-string. – igal Feb 17 '19 at 22:11
  • 1
    solution using for-loop doent work if the output contains spaces; but while-loops works – Pragalathan M Sep 23 '19 at 10:54
  • The "for" loop is the answer I've been looking for! :) – fig Aug 31 '21 at 10:38
  • 2
    A simpler version of <<<$( is < <(. Using here documents causes problems. E.g. they ignore NULL bytes, like when the command find … -print0 is used. –  Jun 13 '22 at 23:20
  • 1
    This answer solves the immediate issue of allowing i to survive past the end of the loop, but does not address the other issues still in the code. Also, note that if the user wants the last value found by find, there are better ways to do this that would not break due to the presence of whitespaces in pathnames. – Kusalananda Mar 25 '23 at 14:58
10
i=1
while read x
do
   i=$(($i + 1))
   echo $i
done < <(find tmp -type f)
echo $i

https://stackoverflow.com/questions/7390497/bash-propagate-value-of-variable-to-outside-of-the-loop

Kamaraj
  • 4,365
  • 1
    This would solve the immediate issue of allowing the variable i to survive past the end of the loop, but the answer does not explain why this works. Also, correcting the many other issues still present in the code would be trivial. – Kusalananda Mar 25 '23 at 14:53