5

This question already has an answer here:

From pseudo terminal /dev/pts/id trying to export key=value from child script, so exported variables has to be passed some how to parent, if possible?

echoing cmd > /proc/$$/fd/0 doesn't execute cmd, only view command in shell terminal emulator, and of course using $(cmd) instead of cmd executes in subshell, and export doesn't add variables to parent process.

EDIT

(1) assuming all the work should be done in the child side.

(2) asked in comments, what i'm trying to achieve? that is a general question, and i'm trying to use the positive answer to pass variables from script executed by parent shell so that user can benefit from added variables without any further work, i.e if script installing application, application should be added in parent shell path.

marked as duplicate by muru, Stephen Rauch, Jeff Schaller, user34720, countermode Jun 22 '17 at 11:53

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • Setting an environment variable in a parent process is not possible from a child. Try adding a description of what it is you want to achieve with this to the question. – Kusalananda Jun 22 '17 at 8:18
  • @Kusalananda edited – Error Jun 22 '17 at 13:54
  • You can't achieve a communication between two processes (whichever their relationship might be: parent → child or not) without a mechanism on both sides: one of them to talk and the other to listen. – daniel Azuelos Jun 27 '17 at 6:02
  • Anwered here for both Linux and Windows: unix.stackexchange.com/questions/38205/… The idea is to pass into child script a temporary directory path, have save files into it and load back in a parent script using introduced help scripts. – Andry Feb 23 at 15:36
8

No, it's not possible.

Environment variables can only be passed from parent to child (as part of environment export/inheritance), not the other way around.

  • any possible hacks? – Error Jun 22 '17 at 3:59
  • @Error, use temporary file to store the variable – Romeo Ninov Jun 22 '17 at 5:55
  • 1
    @Error any possible hacks? There's a nasty hack: attach a debugger to the parent process and have it run setenv( "ENVAL=value" ); See the question linked in the comments above. Something like that is great when someone thinks setting an environment variable to "read-only" in bash actually works. – Andrew Henle Jun 22 '17 at 10:06
  • @RomeoNinov edited – Error Jun 22 '17 at 13:54
  • @AndrewHenle will consider that, question edited though. – Error Jun 22 '17 at 13:57
4

You can transmit variables values from a child to its parent process through a file or a named pipe.

Here is a theoretical simplest example:

child process:

echo ${variable} >/tmp/file

parent process:

read variable </tmp/file
  • question edited – Error Jun 22 '17 at 13:58
2

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

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