Is there a way to change the environment variables of another process in Unix?

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

编辑: 通过 gdb 怎么样?

47441 次浏览

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

更一般的情况... 我不知道,但我怀疑有一个便携式的答案。

(Edited: my original answer assumed the OP wanted to READ the env, not change it)

引用 Jerry Peek 的话:

老狗学不会新把戏。

The only thing you can do is to change the environment variable of the child process before starting it: it gets the copy of the parent environment, sorry.

详情请参阅 http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm

只是一个关于使用/proc 的答案的注释。在 linux/proc 下支持,但是它不工作,即使您是 root 用户,您也可以 不能更改 /proc/${pid}/environ文件: 它是 当然只读的。

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

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

  • 对新进程执行 kill-HUP 以重新读取更新的配置文件,或者
  • have the process check the config file for updates every now and then. If changes are found, then reread the config file.

我可以想出一种相当人为的方法来实现这一点,而且这种方法不适用于任意的过程。

假设您编写了自己的实现‘ char * getenv’的共享库。然后,设置‘ LD _ PRELOAD’或‘ LD _ LIBRARY _ PATH’env。Vars,以便在预加载共享库的情况下运行两个进程。

This way, you will essentially have a control over the code of the 'getenv' function. Then, you could do all sorts of nasty tricks. Your 'getenv' could consult external config file or SHM segment for alternate values of env vars. Or you could do regexp search/replace on the requested values. Or ...

I can't think of an easy way to do that for arbitrary running processes (even if you are root), short of rewriting dynamic linker (ld-linux.so).

实际上,没有。如果你有足够的权限(root 或者其他权限)并且访问/dev/kmem (内核内存) ,你改变了进程的环境,如果进程事后重新引用了环境变量(也就是说,进程还没有获得 env var 的副本,并且没有使用那个副本) ,那么也许,如果你足够幸运和聪明,风向正确,月相正确,也许,你可能会有所成就。

通过广东发展银行:

(gdb) attach process_id


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


(gdb) detach

这是一个相当讨厌的黑客行为,当然,只能在调试场景的上下文中进行。

你也许可以从技术上做到这一点(见其他答案) ,但它可能不会帮助你。

大多数程序都希望在启动之后 env vars 不能从外部进行更改,因此大多数程序可能只是在启动时读取它们感兴趣的 vars 并根据它们进行初始化。因此,事后更改它们不会产生任何影响,因为程序将永远不会重新读取它们。

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

没有直接回答,但是..

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

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

Since the command line is copied into the process’s address space, the process might even write to the memory that holds the command line and modify it. If that happens, then the original command line is lost forever; the only known copy got overwritten.

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

  • difficult to implement
  • 潜在的安全隐患

然而,最可能的原因很简单,那就是这样一个工具的用例有限。

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

我在 Awesome 窗口管理器中使用 很棒的客户改变环境变量,使用的是一个 Lua 代码的 Dbus“ sender”。

看起来 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