Search code examples
bashscopeio-redirectionteeprocess-substitution

Bash: Can Logging Influence Variable Scope?


In my current project, I run a loop that during execution defines a variable that is required later on. Everything worked well until I wanted to add logging with tee, so that I later could inspect the log also in a file. As I wanted to log both, stdout and stderr, I applied |& (the shortcut of 2>&1 |). But strangely, the variable's value gets lost then.

for i in 1 2 3 ; do
    # ... do something meaningful ...
    myVar=test1
done |& tee test1
echo "myVar=$myVar"

Output:

myVar=

Meanwhile I found a way, that works better: When I switch to a combination of file redirection and process substitution, the variable definition works.

for i in 1 2 3 ; do 
    # ... do something meaningful ...
    myVar=test2
done > >(tee test2    ) \
    2> >(tee test2 >&2)
echo "myVar=$myVar"

Output:

myVar=foo

But I want to understand, why :-)

  1. Why does the value get lost in the first example?
  2. Why doesn't it get lost in the second?

Can you tell?


Solution

  • As 123 said a pipe creates a sub shell (a new scope) and a sub shell has no access to the variables of the parent shell.

    The following helper function shows the PID of the shell and the value of the variable a.

    show_a () { echo $BASHPID: a=$a >&2; }
    

    The following example creates no sub shell, because only redirection is used. Only one variable a is used.

    $ a=1; show_a; { a=2; show_a; } > /dev/null ; show_a
    31072: a=1
    31072: a=2
    31072: a=2
    

    But this example creates a sub shell, because of the pipe. And each process has its own variable a.

    $ a=1; show_a; { a=2; show_a; } | tee ; show_a
    31072: a=1
    6375: a=2
    31072: a=1