113

在 Unix 上,有什么方法可以让一个进程更改另一个进程的环境变量(假设它们都由同一个用户运行)?一个通用的解决方案是最好的,但如果不是,那么一个人是另一个孩子的具体情况呢?

编辑:通过 gdb 怎么样?

4

11 回答 11

152

通过 gdb:

(gdb) attach process_id

(gdb) call putenv ("env_var_name=env_var_value")

(gdb) detach

这是一个非常讨厌的 hack,当然只能在调试场景的上下文中完成。

于 2008-10-17T04:19:02.683 回答
22

您可能可以在技术上做到这一点(请参阅其他答案),但它可能对您没有帮助。

大多数程序会期望环境变量在启动后不能从外部更改,因此大多数程序可能只会在启动时读取他们感兴趣的变量并基于此进行初始化。因此,之后更改它们不会有任何影响,因为程序永远不会重新读取它们。

如果您将此作为具体问题发布,您可能应该采取不同的方法。如果只是出于好奇:好问题:-)。

于 2009-02-27T09:43:54.353 回答
14

基本上,没有。如果您有足够的权限(root 或类似权限)并在 /dev/kmem(内核内存)附近进行了操作,并且您对进程的环境进行了更改,并且该进程实际上在之后重新引用了环境变量(即进程尚未获取 env var 的副本并且不只使用该副本),那么也许,如果你幸运且聪明,并且风向正确的方向吹,并且月相是正确的,也许,你可能会有所成就。

于 2008-10-16T17:50:38.927 回答
7

引用杰里·皮克的话:

你不能教老狗新把戏。

您唯一能做的就是在启动子进程之前更改它的环境变量:它会获取父环境的副本,抱歉。

有关详细信息,请参阅http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm

只是对有关使用 /proc 的答案的评论。在 linux /proc 下是支持的,但它不起作用,你不能更改/proc/${pid}/environ文件,即使你是 root:它绝对是只读的。

于 2008-10-15T15:07:49.443 回答
7

我可以想到一种相当人为的方法来做到这一点,它不适用于任意进程。

假设您编写了自己的实现“char *getenv”的共享库。然后,您设置“LD_PRELOAD”或“LD_LIBRARY_PATH”环境。vars 以便您的两个进程都在预加载共享库的情况下运行。

这样,您基本上可以控制“getenv”函数的代码。然后,你可以做各种讨厌的把戏。您的“getenv”可以咨询外部配置文件或 SHM 段以获取 env vars 的替代值。或者您可以对请求的值进行正则表达式搜索/替换。或者 ...

除了重写动态链接器(ld-linux.so)之外,我想不出一种简单的方法来为任意运行的进程(即使你是 root)做到这一点。

于 2008-10-15T15:54:14.077 回答
3

或者让您的流程更新新流程的配置文件,然后:

  • 对新进程执行 kill -HUP 以重新读取更新的配置文件,或者
  • 让进程不时检查配置文件的更新。如果发现更改,则重新读取配置文件。
于 2008-10-15T15:10:58.517 回答
3

似乎putenv现在不起作用,但setenv可以。我正在测试接受的答案,同时尝试在当前 shell 中设置变量但没有成功

$] sudo gdb -p $$
(gdb) call putenv("TEST=1234")
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x0
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=

及其工作方式的变体:

$] sudo gdb -p $$
(gdb) call (int) setenv("TEST", "1234", 1)
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x55f19ff5edc0 "1234"
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=1234
于 2020-05-14T15:35:37.413 回答
2

据我所知不是。实际上,您正在尝试从一个进程与另一个进程进行通信,这需要一种 IPC 方法(共享内存、信号量、套接字等)。通过这些方法之一接收数据后,您可以设置环境变量或更直接地执行其他操作。

于 2008-10-15T15:10:24.977 回答
1

如果您的 unix 支持 /proc 文件系统,那么读取 env 很简单——您可以读取环境、命令行和您拥有的任何进程的许多其他属性。改变它...嗯,我可以想办法,但这是一个坏主意。

更一般的情况......我不知道,但我怀疑是否有可移植的答案。

(已编辑:我的原始答案假设 OP 想要读取环境,而不是更改它)

于 2008-10-15T15:05:36.390 回答
1

不是直接的答案,但是... Raymond Chen 前几天有一个 [基于 Windows] 的理由:-

...虽然肯定有不受支持的方法或在调试器的帮助下工作的方法,但没有任何东西支持以编程方式访问另一个进程的命令行,至少内核没有提供任何东西。...

没有是不跟踪您不需要的信息的原则的结果。内核不需要获取另一个进程的命令行。它获取传递给CreateProcess函数的命令行并将其复制到正在启动的进程的地址空间中,在GetCommandLine函数可以检索它的位置。一旦进程可以访问自己的命令行,内核的职责就完成了。

由于命令行被复制到进程的地址空间,进程甚至可能写入保存命令行的内存并修改它。如果发生这种情况,那么原始命令行将永远丢失;唯一已知的副本被覆盖。

换句话说,任何这样的内核设施都是

  • 难以实施
  • 潜在的安全问题

然而,最可能的原因仅仅是这种设施的用例有限。

于 2009-02-27T09:50:51.200 回答
1

UNIX 充满了进程间通信。检查您的目标实例是否有一些。Dbus 正在成为“桌面”IPC 的标准。

我使用awesome-client更改了Awesome窗口管理器内部的环境变量,它是lua代码的Dbus“发送者”。

于 2011-05-31T12:52:59.950 回答