3

I am trying to export a variable from one script and use it in another script but this variable is not being exported what might be the problem

Consider this as script1

#!/bin/sh
export x=19
exit 0

Consider this as script2

#!/bin/sh
echo "x="${x}
exit 0

i am executing them as two independent scripts like

desktop:~/Desktop/Trail_Programs$ sh script1.sh
desktop:~/Desktop/Trail_Programs$ sh script2.sh

and output is

desktop:~/Desktop/Trail_Programs$ sh script2.sh 
x=
Ap.padole
  • 83
  • 2
  • 7
  • 1
    Among the frequently asked questions in the Stack Overflow [`bash` tag wiki](http://stackoverflow.com/tags/bash/info) you might notice http://stackoverflow.com/questions/17852111/unable-to-export-the-variable-through-script-file and http://stackoverflow.com/questions/4277665/how-do-i-compare-two-string-variables-in-an-if-statement-in-bash -- both of these are very common questions. – tripleee Apr 04 '16 at 05:15

4 Answers4

3

Remember a script may NEVER affect its parent's environment. NEVER means NEVER. So following the rule:

#!/bin/bash
export x=19
exit 0

has NO effect on the environment and does not set x=anything there. The export would only affect the environment of subshells created from within that script. For example take your script, call it exp.sh:

#!/bin/bash
export x=19
./script2.sh
exit 0

and in script2.sh you have:

echo "x = $x"

Then, and only then, will you get:

$ bash exp.sh
x = 19

That's just the rule...

mklement0
  • 382,024
  • 64
  • 607
  • 775
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • 1
    ++; but `./script2.sh` doesn't create a _subshell_, it creates a _child process that happens to be a shell_. Exported variables become environment variables that are visible to _any_ child process, whether it is a shell or not; also, I suggest saying "_cannot_ affect its parent's environment". – mklement0 Apr 04 '16 at 04:19
  • suppose i have to execute these two scripts independently, there is no parent child relationship between the two scripts then what should i do?? – Ap.padole Apr 04 '16 at 04:30
  • You violate the rule. When you need to set something in your environment. you are limited to `/etc/profile` or `/etc/bashrc` or the versions in `$HOME` (e.g. `~/.bashrc`). That is the way Linux shells work. You can `source` code containing variables into the current shell/script, but you cannot effect the parent. Think about where and how `PS1` and `PATH` are set. This is the reason. You can always write a `tmp` file and read that from `script2`, you just cant use the environment. – David C. Rankin Apr 04 '16 at 04:45
  • 1
    @mklement0 as always, you are correct in the phraseology, I could have worded it better... – David C. Rankin Apr 04 '16 at 04:48
  • @DavidC.Rankin writing to a tmp file file creates a tmp~ file and script1 reads data from tmp~ file – Ap.padole Apr 04 '16 at 05:15
2

source script1.sh from script2.sh.

At the start of script2.sh (after the shebang), add:

source /path/to/script1.sh
heemayl
  • 39,294
  • 7
  • 70
  • 76
  • While this may work in some cases, it's generally problematic to source scripts that weren't designed to be sourced. Apart from potentially polluting the calling shell's environment, the bigger concern is `exit` statements in the sourced script (as shown in the OP's sample scripts), as they will inevitably exit the calling shell right away as well. – mklement0 Apr 04 '16 at 12:42
  • @mklement0 duh..missed `exit`..anyway, the primary intuition is to `source` the second script in most similar cases.. – heemayl Apr 04 '16 at 12:44
1

David C. Rankin's helpful answer explains why your code didn't work.

Note:
The following solution should only be used if modifying the scripts you work with is not an option (the solution may also be of interest if you want to learn about sourcing and ad-hoc environment variables).
Otherwise, see the solutions discussed at the bottom.

To solve your problem, you can try the following:

x=$(trap 'printf %s "$x"' EXIT; . script1.sh >/dev/null) sh script2.sh

Note, however, that:

  • script1.sh will - of necessity - be executed by your current shell, which may or may not be sh.
  • script1.sh's stdout output is suppressed, because it must be ensured that printf %s "$x" is the only stdout output produced by the subshell inside the command substitution ($(...)).
  • this approach is limited to a single variable (though it could be extended to output the values of multiple variables that the calling script must then parse back into individual values).

. script1.sh sources the script inside the subshell, which means that the subshell executes script1.sh directly in its own environment and therefore sees the script's variables after executing it (which means it would see $x even if it weren't exported).

trap 'printf %s "$x"' EXIT sets up an exit trap; i.e., code that executes when the subshell exits, in this case printf %s "$x", which simply outputs the value of the variable of interest.
Note that this approach is necessary to ensure that the value of $x is printed even if script1.sh terminates due to an exit statement; since script1.sh is being sourced by the subshell, exit exits the entire subshell.

x=$(...) captures that value, and, by being prepended to command sh script2.sh, effectively makes the resulting $x an environment variable that script2.sh then sees.


It's generally problematic to source scripts that weren't designed to be sourced:

  • all variables modified or created by the script and any changes to the shell environment performed by the script will affect the calling shell.
  • if such scripts execute exit, they will exit the calling shell too.

If the scripts involved cannot be modified for some reason, the solution above is the best choice, because it bypasses these problems, albeit with some limitations.


More robust, generic solutions (modification of the scripts required):

Having the script that sets the environment variable(s) of interest itself invoke the other script is the right solution, as shown in David's answer.

If scripts do need to run as peers, values need to be passed via files: have the script that sets the variable(s) of interest write their values to a (temporary) file and have the other script read that file:

script1.sh:

#!/bin/sh
export x=19
# Write to temp. file named for the *parent* process ID.
# Since both script calls will have the same parent process, this 
# allows you to avoid a static filename subject to name collisions.
printf %s "$x" > /tmp/x.$PPID

script2.sh:

#!/bin/sh
# Read the value of $x from the temp. file, then delete the file.
x=$(cat /tmp/x.$PPID) && rm /tmp/x.$PPID
echo "x=${x}"
Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775
0

Suppose you have file tobeincluded1 with following content

#this file tobeincluded1 will be included in master
x=16

and file tobeincluded2 with following content

#this file tobeincluded2 will be included in master
y=21

you can include the above files in your script using either . or sourcelike below:

#!/bin/bash

. ./tobeincluded1   #using the . to include a file
source ./tobeincluded2 #using the source command to include a file

echo "x : $x"
echo "y : $y"
sjsam
  • 21,411
  • 5
  • 55
  • 102