3

According the bash(1) man pages, when I run the following:

set -e
x=2
echo Start $x
while [ $((x--)) -gt 0 ]; do echo Loop $x; done | cat
echo End $x

The output will be:

Start 2
Loop 1
Loop 0
End 2

After the loop (runs as a subshell) the variable x reset to 2. But if I remove the pipe the x will be updated:

Start 2
Loop 1
Loop 0
End -1

I need to change the x but, I need the pipe too. Any idea how to get around this problem?

Udi
  • 117
  • 8
  • 1
    What does `| cat` do here? Does it do something meaningful? – devnull Jun 04 '13 at 14:45
  • 1
    http://stackoverflow.com/q/4667509/900873 – Kevin Jun 04 '13 at 14:54
  • @devnull, I think it's just there for illustration: that adding a pipe to anything will mean the while loop is run in a subshell, and any changes to variable $x are lost when the subshell ends. – glenn jackman Jun 04 '13 at 15:09
  • Yes, The real loop is long. Inside the loop I have some lines like: ping -c1 Machine || STOP="YES" At the end of the loop I grep(1) out the lines of "icmp_seq=" – Udi Jun 05 '13 at 06:41

1 Answers1

3

bash always (at least as of 4.2) runs all non-rightmost parts of a pipeline in a subshell. If the value of x needs to change in the calling shell, you must rewrite your code to avoid the pipeline.

One horrible-looking example:

# If you commit to one bash feature, may as well commit to them all:
#   Arithmetic compound: (( x-- > 0 ))
#   Process substitution: > >( cat )
while (( x-- > 0 )); do echo Loop $x; done > >( cat )
chepner
  • 497,756
  • 71
  • 530
  • 681