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}"