On piping in shell scripts and var scoping

Memento:

When writing shell scripts keep an eye on subshell creation to avoid unexpected results.

Today I was doing something along these lines:

#!/bin/sh

TOT=0

seq 1 3 | \
while read n;
do
  TOT=$(expr -- $TOT + $n)
  echo $TOT
done

echo $TOT

Which led to this output:
1
3
6
0

Definitely not what I would have expected.

Fortunately the web came to the rescue, see this detailed explanation of what's going on here. It turned out that piping a command into a while loop makes bash to fork a subshell, so the variable values are not preserved when the subshell completes its execution.

You can workaround the issue by putting the output of the command into a HEREDOC string and redirecting that into the loop:

#!/bin/sh

TOT=0

while read n;
do
  TOT=$(expr -- $TOT + $n)
  echo $TOT
done <<EOF 
$(seq 1 3)
EOF

echo $TOT

Which gives:
1
3
6
6


CommentsSyndicate content

Thanks alot! I've been

evil79genius's picture

Thanks alot! I've been looking for such an elegant solution for a long time!

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account associated with the e-mail address you provide, it will be used to display your avatar.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
b
L
g
y
X
B
Enter the code without spaces.