Tra*_*iet 1 environment-variables
我已经看到了相关的问题,比如这个,但他们没有提供确切的回答我的问题
从我的实验以及这个答案,printenv
并env
几乎表现出相同的设定的系统变量。
如果我将变量设置在
/etc/bash.bashrc(应该用于系统范围的系统变量)
SYSTEM_ENVI=1000
Run Code Online (Sandbox Code Playgroud)~/.bashrc (应该用于用户特定的系统变量)
USER_ENVI=10
Run Code Online (Sandbox Code Playgroud)我什至注销并登录,以便 /etc/environment 生效。发生以下场景:
$echo $SYSTEM_ENVI
//outputs 1000
$echo $USER_ENVI
//outputs 10
$CURR_ENVI=1
$env | grep USER_ENVI
//nothing shows up, the same if I grepped SYSTEM_ENVI or CURR_ENVI
$set | grep USER_ENVI
//shows up USER_ENVI assignment, the same if I grepped SYSTEM_ENVI or CURR_ENVI
Run Code Online (Sandbox Code Playgroud)
我的问题是:
printenv
/env
打印?set
查看所有可访问的变量(系统变量和局部变量)而不是printenv
orenv
吗?关于不重复的理由
就我而言,这个问题和明显的答案帮助我意识到以下事实:
我认为我的问题不一定与这个问题不同,但是阅读该问题的标记答案并没有像这篇文章中给出的答案那样让我满意。
env
并且printenv
正在打印由执行它们的命令提供给它们的环境字符串列表(旨在包含环境变量定义)。调用者最终会做一个:
execve("/usr/bin/env", argv, envp);
Run Code Online (Sandbox Code Playgroud)
系统调用 其中argv
和envp
是两个字符串列表。
env
/printenv
只打印 中的字符串列表envp
,每行一个。
按照惯例,在字符串envp
的格式var=value
,但他们没有要(我不知道任何的execve()
执行,强制执行的话),最env
,printenv
实现没有时,他们显示他们不在乎。
当调用者是一个 POSIX shell 时,它将包含在envp
它传递给env
它的被标记为导出的shell 变量列表中(要么因为用户调用了export
/ typeset -x
,要么因为变量已经在 shell 的环境中)启动时收到)。
如果 shell 在启动时收到的某些环境变量无法映射到 shell 变量,或者如果envp
它收到的任何字符串不包含=
字符,则取决于 shell 实现,这些字符串将被传递原封不动,否则外壳会剥去它们或其中的一些。
以 为例bash
,使用 GNUenv
传递任意变量名称列表(env
虽然不能传递任意 envp 字符串,但它们必须包含=
,并且使用的setenv()
不能传递一些以=
¹开头的字符串)。
$ env -i '=foo' '1=x' '+=y' bash -c printenv
+=y
1=x
[...]
Run Code Online (Sandbox Code Playgroud)
(名称为空的变量已被删除,但其他变量未删除)。
此外,如果 shell 收到多个envp
字符串的相同变量名称,根据 shell,它们将全部传递,或者仅传递第一个,或仅传递最后一个。
set
in POSIX shell 打印 shell 变量列表,包括支持数组/散列类型的 shell 的非标量变量,无论它们是否已标记为导出。
在 POSIX shell 中,您还可以export -p
用来列出已标记为导出的变量。与env
/相反printenv
,它还列出了已标记为导出但尚未赋予任何值的变量。
在类似 Korn 的 shell 中,例如ksh
, zsh
or bash
,您还可以使用它typeset
来获取更多信息,包括变量的属性,以及按类型列出变量(例如typeset -a
列出数组变量)。
在这里,通过添加USER_ENVI=10
到您的~/.bashrc
,您正在配置bash
shell的交互式非登录调用,以在启动时定义一个USER_ENVI
shell变量。由于您没有使用export
,该变量仍然是一个 shell 变量(除非它在bash
启动时在环境中),所以它不会作为环境变量传递给由该 shell 执行的命令。
/etc/environment
本身,在 Ubuntu 16.04 上由pam_env.so
可插拔身份验证模块读取。用来记录你在喜欢的应用程序login
,sshd
,lightdm
将如果配置了读取这些文件pam_env.so
中/etc/pam.d
,并通过相应的环境变量(无关这里shell变量),他们在通过身份验证后(如登录shell你的名字启动命令login
/ sshd
,或您的图形会话管理器lightdm
...)。
由于环境是默认继承的,当你的会话管理器执行一个终端模拟器,然后执行你的登录 shell 时,这些环境变量将在每一步传递,你的 shell 会将它们映射到 shell 变量,你可以在命令中扩展这些变量符合之类的东西echo "$VAR"
。
pam_env
env 文件/etc/environment
看起来像 shell 脚本,但pam_env
不调用 shell 来解析它们并且只理解 shell 语法的一个子集,并且只允许定义名称由一个或多个 ASCII 字母数字字符或下划线组成的变量(它确实让您定义一个123
变量,尽管它不是有效的 POSIX shell 变量名)。
¹,要传递任意环境字符串的列表,您还可以execve()
直接调用:
perl -e 'require "syscall.ph";
$cmd = "/bin/zsh";
$args = pack("p*x[p]", "sh", "-c", "printenv");
$env = pack("p*x[p]", "a=b", "a=c", "", "+=+", "=foo", "bar");
syscall(SYS_execve(), $cmd, $args, $env)'
Run Code Online (Sandbox Code Playgroud)
在这里测试zsh
而不是bash