Increment a global variable in Bash

zserge picture zserge · Nov 23, 2010 · Viewed 20k times · Source

Here's a shell script:

globvar=0

function myfunc {
  let globvar=globvar+1
  echo "myfunc: $globvar"
}

myfunc
echo "something" | myfunc

echo "Global: $globvar"

When called, it prints out the following:

$ sh zzz.sh
myfunc: 1
myfunc: 2
Global: 1
$ bash zzz.sh
myfunc: 1
myfunc: 2
Global: 1
$ zsh zzz.sh
myfunc: 1
myfunc: 2
Global: 2

The question is: why this happens and what behavior is correct?

P.S. I have a strange feeling that function behind the pipe is called in a forked shell... So, can there be a simple workaround?

P.P.S. This function is a simple test wrapper. It runs test application and analyzes its output. Then it increments $PASSED or $FAILED variables. Finally, you get a number of passed/failed tests in global variables. The usage is like:

test-util << EOF | myfunc
input for test #1
EOF
test-util << EOF | myfunc
input for test #2
EOF
echo "Passed: $PASSED, failed: $FAILED"

Answer

Dennis Williamson picture Dennis Williamson · Nov 23, 2010

Korn shell gives the same results as zsh, by the way.

Please see BashFAQ/024. Pipes create subshells in Bash and variables are lost when subshells exit.

Based on your example, I would restructure it something like this:

globvar=0

function myfunc {
    echo $(($1 + 1))
}

myfunc "$globvar"
globalvar=$(echo "something" | myfunc "$globalvar")