env 和 printenv 显示哪些环境变量/shell 变量

env 和 printenv 显示哪些环境变量/shell 变量

我看过相关问题,例如但他们没有提供我问题的确切答案

从我的实验以及这个答案printenv并且env几乎显示同一组系统变量。

如果我将变量设置为

  1. /etc/bash.bashrc (应该是系统范围的系统变量)

    SYSTEM_ENVI=1000
    
  2. ~/.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

我的问题是:

  1. printenv执行/打印哪些系统变量env
  2. 应该使用set查看所有可访问变量(系统变量和局部变量)而不是printenvorenv吗?

关于不重复的理由

就我而言,这个问题和标记的答案帮助我认识到以下事实:

  1. shell变量不是环境变量
  2. 作业于/etc/bash.bashrc或者~/.bashrc不创建环境变量,而是指示交互式非登录 shell 进程创建和初始化这些变量外壳变量关于初创公司。

我认为我的问题不一定与这个但阅读该问题的标记答案并没有像这篇文章中给出的答案那样令我满意。

答案1

envprintenv打印由执行它们的命令提供给它们的环境字符串列表(旨在包含环境变量定义)。调用者最终会执行以下操作:

execve("/usr/bin/env", argv, envp);

系统调用,其中argvenvp是两个字符串列表。

env/printenv只打印 中的字符串列表envp,每行一个。

按照惯例, 中的字符串envp采用 format var=value,但它们不必是(我不知道有任何execve()强制执行它的实现),并且大多数env实现printenv并不关心何时显示它们。

当调用者是 POSIX shell 时,它将包含在envp传递给env标记为 的 shell 变量列表中出口(要么是因为用户在其上调用了export/ typeset -x,要么是因为该变量已经在 shell 启动时接收到的环境中)。

如果 shell 在启动时收到的某些环境变量无法映射到 shell 变量,或者如果envp它收到的任何字符串不包含=字符,则根据 shell 实现,这些字符串将被传递不受影响,否则外壳会剥去它们或其中一些。

例如bash,使用 GNUenv传递任意变量名称列表(env但不能传递任意 envp 字符串,它们必须包含 a =,并且使用的字符串setenv()不能传递以=1 开头的变量)。

$ env -i '=foo' '1=x' '+=y' bash -c printenv
+=y
1=x
[...]

(名称为空的变量被删除,但其他变量未被删除)。

另外,如果 shell 收到envp同一变量名的多个字符串,则根据 shell 的不同,它们将全部传递,或者仅传递第一个字符串,或者仅传递最后一个字符串。

set在 POSIX shell 中打印 shell 变量列表,包括支持数组/散列类型的 shell 的非标量变量,无论它们是否已标记为导出。

在 POSIX shell 中,您还可以用来export -p列出已标记为导出的变量。与env/相反printenv,它还列出了已标记为导出但尚未赋予任何值的变量。

在类似 Korn 的 shell 中,如ksh,zshbash,您还可以使用typeset来获取更多信息,包括变量的属性,并按类型列出变量(如typeset -a列出数组变量)。

在这里,通过添加USER_ENVI=10到您的~/.bashrc,您可以配置 shell 的交互式非登录调用bash来定义USER_ENVI 启动时变量。由于您没有使用过export,该变量仍然是 shell 变量(除非它在启动时位于环境中bash),所以它不会作为环境该 shell 执行的命令的变量。

/etc/environment本身在 Ubuntu 16.04 上由可插入身份验证模块读取pam_env.so。登录的应用程序(如loginsshd、 )lightdm将读取这些文件(如果配置为使用pam_env.so/etc/pam.d传递相应的文件)环境变量(与此处的 shell 变量无关)到在您进行身份验证后它们以您的名字启动的命令(例如login/的登录 shellsshd或...的图形会话管理器lightdm)。

由于默认情况下会继承环境,因此当您的会话管理器执行终端仿真器(该终端仿真器又执行您的登录 shell)时,这些环境变量将在每个步骤中传递,并且您的 shell 会将它们映射到您可以在命令中展开的 shell 变量符合诸如 之类的东西echo "$VAR"

pam_envenv 文件/etc/environment看起来像 shell 脚本,但pam_env不会调用 shell 来解析它们,并且仅理解 shell 语法的子集,并且只允许定义名称由一个或多个 ASCII 字母数字字符或下划线组成的变量(它确实让您定义一个123变量,尽管它不是有效的 POSIX shell 变量名)。


1,要传递任意环境字符串的列表,您还可以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)'

在这里测试而zsh不是bash

答案2

通过做:

USER_ENVI=10

您正在设置一个变量,但不是环境变量。为此,您需要:

export USER_ENVI=10

或者

USER_ENVI=10; export USER_ENVI

这是合理的,这对你不起作用:

$ env | grep SYSTEM_ENVI

没有名为SYSTEM_ENVIset 的环境变量。我们对此无话可说,/etc/environment因为您尚未发布其内容(似乎也没有使用它)。

将打印的内容env与应该打印的内容完全相同printenv(没有选项)。

答案:

  1. env 和 printenv 都会报告与实际设置完全相同的变量列表投资基金命令后没有选项或变量列表。

  2. 您可以使用 set (不带选项)来查看所有变量集。这并不意味着你必须用它。这取决于您想要列出的内容。仅列出环境变量列表是完全有效且正确的。

相关内容