3

a simple variable test:

#!/bin/bash

N=0

ls -l | while read L; do
 N=$((N+1))
 echo $N
done

echo "total $N"

ran it then output:

1
2
3

total 0

i expected final N=3: "total 3", but why did the value reset to 0 after the loop?

2
  • 1
    solved as a known subshell issue. check out stackoverflow.com/questions/5006229/… Commented Nov 10, 2011 at 21:22
  • you can replace the $((N+1)) with ((N++)) with the same result Commented Nov 10, 2011 at 22:10

1 Answer 1

8

bash runs each statement in a pipe in its own subshell. (For external commands such as ls the subshell simply execs the command.) This effectively makes all of the variables local. You generally have to work around this by using redirection or command substitution instead of a pipe.

EDIT: This seems to work:

#!/bin/bash
IFS=
N=0

while read L; do
  N=$((N+1))
  echo $N
done <<<$(ls -l)

echo "total $N"

EDIT: As of bash 4.2 you can use shopt -s lastpipe in your script to disable the subshell for the last command in a pipe, which would then allow the rest of the original code to work as desired.

Sign up to request clarification or add additional context in comments.

2 Comments

What's the logic behind redirection? Why exactly it prevents the while loop from subshelling?
@olimpiabaku Actually it's piping which makes bash subshell the while loop, although as of bash 4.2 you can disable this in a script (see my edit).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.