我已经看到了诸如此类的相关问题,但他们没有为我的问题提供确切的答案
从我的实验以及这个答案来看,printenv
几乎env
都显示了相同的系统变量集。
如果我将变量设置为
/etc/bash.bashrc(应该是系统范围的系统变量)
SYSTEM_ENVI=1000
~/.bashrc (应该是用户特定的系统变量)
USER_ENVI=10
我什至注销并登录,因此 /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
我的问题是:
- 什么系统变量做
printenv
/env
打印? - 应该使用
set
查看所有可访问变量(系统变量和局部变量)而不是printenv
orenv
吗?
关于不重复的理由
就我而言,这个问题和明显的答案帮助我认识到以下事实:
- Shell 变量不是环境变量
- /etc/bash.bashrc或~/.bashrc中的赋值不会创建环境变量,而是指示交互式非登录 shell 进程在启动时创建和初始化这些shell 变量。
我认为我的问题不一定与这个问题不同,但是阅读那个问题的标记答案并不像这篇文章中给出的答案那样让我满意。
env
并printenv
打印由执行它们的命令提供给它们的环境字符串列表(意味着包含环境变量定义)。调用者最终将执行以下操作:系统调用 where
argv
和envp
是两个字符串列表。env
/printenv
只打印 中的字符串列表envp
,每行一个。按照惯例,其中的字符串
envp
采用 formatvar=value
,但它们不一定是(我不知道有任何execve()
实现它的实现),并且大多数env
实现printenv
并不关心它们何时显示它们。当调用者是 POSIX shell 时,它将包含在
envp
它传递给标记为导出env
的 shell 变量列表中(因为用户在其上调用/ ,或者因为变量已经在 shell 的环境中)启动时收到)。export
typeset -x
如果 shell 在启动时收到的某些环境变量无法映射到 shell 变量,或者如果
envp
它收到的任何字符串不包含=
字符,则取决于 shell 实现,这些字符串将被传递原封不动,否则外壳会剥去它们或其中的一些。例如
bash
,使用 GNUenv
传递任意变量名称的列表(env
虽然不能传递任意 envp 字符串,但它们必须包含 a=
,并且使用的那些setenv()
不能传递以=
¹ 开头的一些)。(具有空名称的变量已删除,但其他变量未删除)。
此外,如果 shell 接收
envp
到同一个变量名的多个字符串,取决于 shell,它们将全部传递,或者只传递第一个,或者只传递最后一个。set
in POSIX shells 打印 shell 变量列表,包括支持数组/哈希类型的 shell 的非标量变量,无论它们是否已标记为导出。在 POSIX shell 中,您还可以使用
export -p
列出已标记为导出的变量。与env
/相反printenv
,它还列出了已标记为导出但尚未被赋予任何值的变量。在类似 Korn 的 shell
ksh
中,如zsh
或bash
,您还可以使用typeset
来获取更多信息,包括变量的属性,以及按类型列出变量(如typeset -a
列出数组变量)。在这里,通过添加
USER_ENVI=10
您的~/.bashrc
,您正在配置 shell 的交互式非登录调用,以在启动时bash
定义一个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 变量名的变量)。¹,要传递任意 env 字符串列表,您也可以
execve()
直接调用:在这里测试
zsh
而不是bash
通过做:
您正在设置一个变量,但不是一个环境变量。为此,您需要:
或者
这对您不起作用是合理的:
没有称为
SYSTEM_ENVI
set 的环境变量。/etc/environment
由于您尚未发布其内容(似乎也没有使用它),因此我们无话可说。将打印的内容与应打印
env
的内容完全相同printenv
(没有选项)。答案:
如果命令后没有选项或变量列表,则env 和printenv都将报告与实际设置的变量列表完全相同的列表。
您可以使用 set(不带选项)查看所有变量集。这并不意味着您必须使用它。这取决于您要列出的内容。仅列出环境变量列表是完全有效和正确的。