简体   繁体   中英

Sharing variables between two independent shell scripts

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=

source script1.sh from script2.sh .

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

source /path/to/script1.sh

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...

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 . 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; ie, 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}"

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 source like 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"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM