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)?

  • 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). – 0xC0000022L Oct 24 '19 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? – Alexei Martianov Oct 24 '19 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). – 0xC0000022L Oct 24 '19 at 6:06
  • @0xC0000022L, thank you! would be good (IMHO) if you include that valuable comment in your answer. – Alexei Martianov Oct 24 '19 at 6:18
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.

| improve this answer | |
  • thanks a lot! part of my confusion was due to me missing . before script name in section about sourcing - I added AMEND section. – Alexei Martianov Oct 24 '19 at 6:17
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).

| improve this answer | |
  • thank you, please see my ADDED SECTION. – Alexei Martianov Oct 24 '19 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 '19 at 5:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.