Search code examples
bashfunctionvariablessleep

How exactly does the trap EXIT function and the "sleep n && function" operate in bash with regards to variables?


Here is a script that reproduces my problem. The function echos and changes the variable. It doesn't matter if I press a key first or let the timer run out first, the variable does not change for both calls, it just prints "Not touched!" twice, which is very strange to me.

#!/bin/bash

func(){
    echo "$globalVar"       
    globalVar="touched!"
}

globalVar="Not touched!"

trap func EXIT
(sleep 3 && func) &

read -n1 -r -p "Press any key to exit..."

I expect it to echo "Not touched!" the first time and "toched!" the second time.

Edit: Has to do with the (sleep 3 && func) $ line using a background process. My question then would be how do I make the variable really global?


Solution

  • Traps

    The trap built-in is specified by posix sh and bash is bound by that specification. From the official specification:

    The environment in which the shell executes a trap on EXIT shall be identical to the environment immediately after the last command executed before the trap on EXIT was taken.

    Each time trap is invoked, the action argument shall be processed in a manner equivalent to:

    eval action

    That should answer the question in your title. However, your script is affect by another other detail that can be a bit confusing:

    Subshells

    Inside a subprocess, you cannot change the variables of the parent process. This might seem obvious if you have a command like ...

    #! /bin/bash
    x=1
    bash -c 'x=2'
    echo "$x"
    

    ... but bash starts so called subshells in a lot of places, e.g. in pipes (subshell1 | subshell2), substitutions command "$(subshell)", background processes subshell & and explicit subshells (subshell).

    (sleep 3 && func) & runs in a subshell and therefore cannot alter the global variable of the parent process.

    Inter-Process Communication

    My question then would be how do I make the variable really global?

    If you want to have a shared variable between two processes, that's simply not possible with built-ins. You need some way to do inter-process communication. The simplest solution for that in shells is to read and write files/fifos. The details depend on what exactly you are trying to achieve.