是否可以在用户空间中将环境变量从子级传递到父级?

Err*_*ror 15 shell process environment-variables

正如标题所说,我希望能够从子进程(通常是脚本)更改父进程(特别是 shell)中的环境变量。从/dev/pts/id试图key=value从子脚本导出的伪终端,如果可能的话,导出的变量必须以某种方式传递给父脚本?

echoingcmd > /proc/$$/fd/0不执行cmd,只在 shell 终端模拟器中查看命令,当然在 subshel​​l 中使用$(cmd)而不是cmd执行,并且export不向父进程添加变量。

  1. 我更喜欢所有的工作都在孩子这边完成。

  2. 我在评论中被问到,我想要实现什么?这是一个普遍的问题,我正在尝试使用肯定的答案从(父)shell 执行(生成)的脚本中传递变量,以便用户可以从添加的变量中受益,而无需任何进一步的工作。比如我想用脚本安装一个应用程序,应用程序目录应该添加到父shell路径中。

hee*_*ayl 16

不,这不可能。

环境变量只能从父级传递到子级(作为环境导出/继承的一部分),而不是相反。


dan*_*dan 5

您可以通过文件或命名管道将变量值从子进程传输到其父进程。

这是一个理论上最简单的例子:

子进程:

echo ${variable} >/tmp/file
Run Code Online (Sandbox Code Playgroud)

父进程:

read variable </tmp/file
Run Code Online (Sandbox Code Playgroud)


G-M*_*ca' 5

如果父进程不期待并与之合作,这将非常棘手。在这种情况下,请参阅更改正在运行的进程的环境 以及是否有办法更改另一个进程的环境变量?

如果父进程期望值并配合传输,简单的方法是使用命令替换:

导出VAR =$( cmd )

这假设变量的值是程序想要写入的唯一内容。如果子进程需要能够写入屏幕(特别是父进程的标准输出),我们可以通过将父进程的文件描述符 1 隐藏在另一个文件描述符中来实现:

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.
Run Code Online (Sandbox Code Playgroud)

现在,如果child_prog简短而简单,最简单的方法可能是将变量的值写入文件描述符 1 并使用文件描述符 3 ( cmd?>&3) 作为标准输出。如果它很大和/或复杂,您将需要执行以下操作:

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.
Run Code Online (Sandbox Code Playgroud)

然后正常使用stdout,并>&5用于写入值。

到目前为止,我一直假设您只想将一个值传递给一个变量。如果您有多个值,用一个字符(或字符串)分隔它们很简单,保证不会出现在任何值中。如果我们选择@@,那么父母可以说

exec 3>&1
temp=$(child_prog)
exec 3>&-
export var1="${temp%%@@*}"
rest="${temp#*@@}"
export var2="${rest%%@@*}"
export var3="${rest#*@@}"
Run Code Online (Sandbox Code Playgroud)

和孩子可以说 。echo "value1@@value2@@value3"?>&5

如果很难找到保证不会出现在任何值中的打印字符字符串,则可以使用换行符。只需@@在上述命令中更改为换行符:

家长:

export var1="${temp%%
*}"
rest="${temp#*
}"
export var2="${rest%%
*}"
export var3="${rest#*
}"
Run Code Online (Sandbox Code Playgroud)

孩子:

printf "%s\n" " value1 " " value2 " " value3 "?>&5


另一种变化是让孩子将命令 而不是值反馈给父母。如果父进程说.?<(child_prog),它运行子进程,捕获输出并执行它。然后孩子可以做

printf "export var1=' value1 '\nexport var2=' value2 ' var3=\" value3 \"\n" >&5

(我用value3包含撇号的a 测试了这个,所以我不得不用 引用它\"…\",我把它留在那里只是为了说明替代语法。)

此技术的一个特点是您可以添加要导出的变量,而无需更改父级中的代码。

这种方法要求父进程运行 bash(或者可能是其他高级 shell 之一?),因为 POSIX 不支持.<(cmd)