Search code examples
bashzshexec

`exec` is accessing local variables


I'm learning about bash and zsh. One command I came across was exec. I know that it will replace the current process with the supplied command. By what I have read over the internet, the local variables will not be inherited in the replaced process of exec. I tested it and failed. I am using zsh 5.9 on MacOS 14.

Here is what I wrote,

> a=2
> exec echo $a
2

process exited...

I thought it might be due to parameter expansion and I tried the following

> a=2
> exec echo '$a'
$a

process exited...

Since it printed $a, I'm guessing that parameter expansion didn't happen. Otherwise, the single quotes would have been removed and $a would have been treated as an expansion instead of a string.

To further verify if the variable was inherited or not, I used the declare command. The output is as follows

> aa=2
> exec declare -p | grep aa
typeset aa=2

Even this shows the local variable.

Since exec doesn't inherit the local variables, why is it happening? I don't think it is only related to zsh.


Solution

  • Yes, $a is expanded first, then exec receives the arguments echo and 2.

    With single quotes, exec receives the arguments echo and $a.

    In bash, exec declare -p should fail, as declare is a shell built-in command, not an executable.

    In zsh, using the built-in declare does not cause exec to fail, but is executed in the current shell, and then the current shell exits. (Because you used a pipeline, though, the current shell is a subshell that "copied" the parent, and that's what exits.) You can consider that inheritance if you like, but it's special zsh behavior, not related to the POSIX definition of exec.


    From man zshbuiltins:

    exec [ -cl ] [ -a argv0 ] [ command [ arg ... ] ]

    Replace the current shell with command rather than forking. If command is a shell builtin command or a shell function, the shell executes it, and exits when the command is complete.