This is very tricky
if the parent process is not expecting and cooperating with it.
In that case, see change environment of a running process
and Is there a way to change another process's environment variables?
If the parent process is expecting the value
and cooperating with the transfer,
the simple way is to use command substitution:
export VAR=$(cmd)
This assumes that the value of the variable
is the only thing the program wants to write.
If the child process needs to be able to write to the screen
(specifically, the parent’s stdout),
we can do that by hiding the parent’s file descriptor 1
in another file descriptor:
exec 3>&1 # Copy our file descriptor 1 into file descriptor 3.
# child_prog will be invoked with file descriptor 1 pointing to a pipe
# for the command substitution, but all other file descriptors intact.
# Specifically, fd3 will point to our stdout.
export var=$(child_prog)
exec 3>&- # (Optionally) close fd3 as cleanup.
Now, if child_prog
is short and simple,
it may be easiest simply to write the value for the variable
to file descriptor 1
and use file descriptor 3 (cmd >&3
)
as the standard output.
If it’s large and/or complex, you’ll want to do something like:
exec 5>&1 # Redirect fd1 (the command substitution pipe) to fd5.
exec 1>&3 # Set our fd1 (stdout) to our parent's stdout (which was passed in as fd3).
exec 3>&- # Close fd3; it’s no longer needed.
and then use stdout normally, and use >&5
for writing the value.
So far I’ve been assuming that
you want to pass only one value to one variable.
If you have multiple values,
it’s a simple matter of delimiting them with a character (or string)
that’s guaranteed not to appear in any of the values.
If we select @@
, then the parent can say
exec 3>&1
temp=$(child_prog)
exec 3>&-
export var1="${temp%%@@*}"
rest="${temp#*@@}"
export var2="${rest%%@@*}"
export var3="${rest#*@@}"
and the child can say
echo "value1@@value2@@value3" >&5
.
If it’s hard to find a string of printing characters
that’s guaranteed not to appear in any of the values, you can use newline.
Just change @@
to newline in the above commands:
Parent:
export var1="${temp%%
*}"
rest="${temp#*
}"
export var2="${rest%%
*}"
export var3="${rest#*
}"
Child:
printf "%s\n" "value1" "value2" "value3" >&5
Yet another variation is to have the child feed commands
back to the parent, rather than values.
If the parent says . <(child_prog)
,
it runs the child, captures the output, and executes it.
Then the child can do
printf "export var1='value1'\nexport var2='value2' var3=\"value3\"\n" >&5
(I tested this with a value3
that contained an apostrophe,
so I had to quote it with \"…\"
,
and I left it that way just to illustrate the alternative syntax.)
A feature of this technique is that you can add variable(s)
to be exported without changing the code in the parent.
This approach requires that the parent process be running bash
(or maybe one of the other advanced shells?),
since POSIX doesn’t support <(cmd)
.
source
as I answered above), then it should work.bash
, it's for security and reliability. You don't want to just any script you call to mess up your current script's functioning. If you choose tosource
a script, that requires a higher level of trust and understanding about what it does.