53 linux process environment-variables
Linux/proc/<pid>/environ不会更新进程的环境。据我了解,该文件包含进程的初始环境。
如何读取进程的当前环境?
Jon*_*ham 48
您可以从 读取进程的初始环境/proc/<pid>/environ。
如果一个进程改变了它的环境,那么为了读取该环境,您必须拥有该进程的符号表并使用ptrace系统调用(例如通过使用gdb)从全局char **__environ变量中读取环境。没有任何其他方法可以从正在运行的 Linux 进程中获取任何变量的值。
这就是答案。现在做一些笔记。
以上假设该流程符合 POSIX,这意味着该流程使用Ref Spec 中char **__environ指定的全局变量来管理其环境。
进程的初始环境在进程堆栈上的固定长度缓冲区中传递给进程。(执行此操作的通常机制是linux//fs/exec.c:do_execve_common(...)。)由于计算出的缓冲区大小不超过初始环境所需的大小,因此您无法在不擦除现有变量或粉碎堆栈的情况下添加新变量。因此,任何允许更改进程环境的合理方案都将使用堆,其中可以分配和释放任意大小的内存,这正是 GNU libc( glibc) 为您所做的。
如果进程使用glibc,那么它是符合 POSIX 的,__environ在glibc//posix/environ.cGlibc中声明__environ它用一个指向它malloc来自进程堆的内存的指针进行初始化,然后将初始环境从堆栈复制到这个堆区域。进程每次使用该setenv函数时,都会glibc执行 arealloc来调整__environ指向以容纳新值或变量的区域的大小。(您可以使用 下载 glibc 源代码git clone git://sourceware.org/git/glibc.git glibc)。要真正理解该机制,您还必须阅读hurd//init/init.c:frob_kernel_process()(git clone git://git.sv.gnu.org/hurd/hurd.git hurd) 中的 Hurd 代码。
现在,如果新进程仅被forked,而没有后续exec覆盖堆栈,则参数和环境复制魔术在 中完成linux//kernel/fork.c:do_fork(...),其中copy_process例程调用通过调用dup_task_struct来分配新进程的堆栈alloc_thread_info_node,它使用 为新进程调用setup_thread_stack( linux//include/linux/sched.h) alloc_thread_info_node。
最后,POSIX__environ约定是用户空间约定。它与 Linux 内核中的任何内容都没有联系。您可以在不使用glibc和不使用__environ全局变量的情况下编写用户空间程序,然后根据需要管理环境变量。没有人会因为您这样做而逮捕您,但您必须编写自己的环境管理函数 ( setenv/ getenv) 和自己的包装器,sys_exec而且很可能没有人能够猜出您将更改放置到环境的位置。
Gil*_*il' 26
/proc/$pid/environ如果进程改变它自己的环境,它会更新。但是很多程序并不费心去改变自己的环境,因为这有点没有意义:一个程序的环境不是通过正常渠道可见的,只能通过/procand ps,甚至不是每个unix变体都有这种特性,所以应用程序不依赖在上面。
就内核而言,环境仅作为execve启动程序的系统调用的参数出现。Linux 通过 公开内存中的一个区域/proc,一些程序更新这个区域,而其他程序则不更新。特别是,我认为任何 shell 都不会更新这个区域。由于该区域具有固定大小,因此无法添加新变量或更改值的长度。
Nik*_*ley 24
它在进程获取/删除其环境变量时更新。您是否有参考environ文件说明该文件未在 /proc 文件系统下的进程目录中为进程更新?
xargs --null --max-args=1 echo < /proc/self/environ
Run Code Online (Sandbox Code Playgroud)
或者
xargs --null --max-args=1 echo < /proc/<pid>/environ
Run Code Online (Sandbox Code Playgroud)
或者
ps e -p <pid>
Run Code Online (Sandbox Code Playgroud)
以上将以ps输出格式打印进程的环境变量,需要文本处理(解析/过滤)以列表形式查看环境变量。
Solaris(没有被问到,但作为参考,我会在这里发布):
/usr/ucb/ps -wwwe <pid>
Run Code Online (Sandbox Code Playgroud)
或者
pargs -e <pid>
Run Code Online (Sandbox Code Playgroud)
编辑: /proc/pid/environ 未更新!我站着纠正。验证过程如下。但是,进程派生的子进程将继承进程环境变量,并且它在各自的 /proc/self/environ 文件中可见。(使用字符串)
在 shell 中:这里 xargs 是一个子进程,因此继承了环境变量并反映在它的/proc/self/environ文件中。
[centos@centos t]$ printenv | grep MASK
[centos@centos t]$ export MASK=NIKHIL
[centos@centos t]$ printenv | grep MASK
MASK=NIKHIL
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
MASK=NIKHIL
[centos@centos t]$ unset MASK
[centos@centos t]$ printenv | grep MASK
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
[centos@centos t]$
Run Code Online (Sandbox Code Playgroud)
从其他会话中检查它,其中终端/会话不是设置环境变量的 shell 的子进程。
从同一主机上的另一个终端/会话进行验证:
terminal1: : 请注意,printenv 是分叉的并且是 bash 的子进程,因此它读取自己的环境文件。
[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$
Run Code Online (Sandbox Code Playgroud)
terminal2:在同一台主机上——不要在设置了上述变量的同一个 shell 中启动它,单独启动终端。
[centos@centos ~]$ echo $$
4436
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/self/environ | grep -i spidey
[centos@centos ~]$ strings -f /proc/2610/environ | grep -i spidey
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/2610/environ | grep -i spidey
[centos@centos ~]$
Run Code Online (Sandbox Code Playgroud)
fib*_*cci 14
那么下面的内容与作者的真实意图无关,但如果你真的想“阅读” /proc/<pid>/environ,你可以尝试
strings /proc/<pid>/environ
Run Code Online (Sandbox Code Playgroud)
这比cat它好。