0

I did web search and have read several articles on using variables in bash, including wiki but could not understand why running in bash FOO_VARIABLE=foo;./test does not result in test having $FOO_VARIABLE being foo:

By default, when a process is created, it inherits a duplicate environment of its parent process, except for explicit changes made by the parent when it creates the child.

Also have read that: Exception of inheritance of environment variables

"except for explicit changes": FOO_VARIABLE=foo ./test - results in test script knowing FOO_VARIABLE, but why in first way it does not?

echo $0
-bash

cat ./test
echo $MY_TEST
MY_TEST=test$MY_TEST
echo $MY_TEST

MY_TEST=ret;./test

test

Tested on CentOS 7 and Mac OS.

ADDED: https://stackoverflow.com/questions/9772036/pass-all-variables-from-one-shell-script-to-another second way is to source (2nd script is called from 1st), then no export needed - why my case is different?

AMEND to above: it was my rush and not very attentiveness to details: I missed . (dot) in sourcing section, now I've read: https://superuser.com/questions/176783/what-is-the-difference-between-executing-a-bash-script-vs-sourcing-it and that part is all clear.

https://askubuntu.com/questions/26318/environment-variable-vs-shell-variable-whats-the-difference Yes, mine is local, but why is it not passed via inheritance (fork call)?

4
  • 1. I'm not sure why you state that your case is different. Which answer are you referring to? Your case seems equivalent. 2. It will be inherited in fact. But only by a subshell, not by arbitrary process. I.e. you can see it best here: TEST=ret; (echo "shell variable=$TEST"; env|grep TEST). Oct 24, 2019 at 5:53
  • @0xC0000022L, so when script is run from other script it creates subshell, but when in interactive shell I run script - that script is NOT run in subshell? why is that? Oct 24, 2019 at 6:00
  • 1
    No, a subshell has its own settings (e.g. shell options and working directory) but technically runs in the same process. So there's no fork() involved. If there's a fork() command line arguments and environment variables would be the way to make the other script see the variable. For example if you used source ./test to bring all the statements from ./test into your current shell, the variable would also be visible, because you don't actually start another process (assuming ./test is written in the same shell dialect as the running shell). Oct 24, 2019 at 6:06
  • @0xC0000022L, thank you! would be good (IMHO) if you include that valuable comment in your answer. Oct 24, 2019 at 6:18

2 Answers 2

2

In the first command,

FOO_VARIABLE=foo;./test

you assign the shell variable FOO_VARIABLE a value. Then you call ./test. Since FOO_VARIABLE is not exported, it is not an environment variable and it will therefore not be inherited by any script or program that you run. This is why ./test does not know about the variable.

In short: You set the shell variable "here" but it will not be available "there" (in ./test).

In the other command,

FOO_VARIABLE=foo ./test

you set the value of FOO_VARIABLE in the environment of ./test (i.e. you create an environment variable fro ./test called FOO_VARIABLE). The variable is not set in the current environment as an environment variable nor as a shell variable, only for the process resulting from running ./test.

In short: You set the environment variable "there" (in ./test) but not "here".

If you have an existing variable FOO_VARIABLE that you want a script or program to inherit as a environment variable, you will have to export it, i.e. make an environment variable from it:

FOO_VARIABLE=foo
export FOO_VARIABLE
./test

or, shorter

export FOO_VARIABLE=foo
./test

This sets the variable locally as well as makes it available in any created process (in ./test for example).

2
  • thank you, please see my ADDED SECTION. Oct 24, 2019 at 5:49
  • 2
    @AlexeiMartianov "Local" variable (shell variable) are not inherited across fork(). This is how they are different from environment variables (exported variables).
    – Kusalananda
    Oct 24, 2019 at 5:58
1

Because at this point it's not an environment variable, it's a shell/local variable. You need to export MY_TEST it for this to work. An alternative would be this:

env MY_TEST=ret ./test

(In Bash also simply MY_TEST=ret ./test, but with env is more portable across shells.)

You could, by the way, verify this also by replacing your ./test with env|grep MY_TEST.

In Bash (but not all other shells) you can also say

Executing it on the shell prompt will - in this case - be equivalent to what you'd be doing in a script.

Use:

export MY_TEST=ret; env|grep MY_TEST

to verify what I wrote.

Assuming ./test were a shell script (of the same shell dialect) you could also use

source ./test

... to bring all the statements from ./test into your current shell. The the shell/local variable would also be visible, because you don't actually start another process.

A subshell has its own settings (e.g. shell options and working directory) but technically runs in the same process. So there's no fork() involved. If there's a fork() command line arguments and environment variables would be the way to pass stuff to the other script/executable.


It's different from the case where a subshell inherits the parent shell's shell/local variables:

TEST=ret; (echo "shell variable=$TEST"; env|grep TEST)

Here the subshell (inside (...)) will see the variable, but it's still not an environment variable.

1
  • thanks a lot! part of my confusion was due to me missing . before script name in section about sourcing - I added AMEND section. Oct 24, 2019 at 6:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .