究竟什么是环境变量?

Mat*_*att 45 shell bash environment-variables

我知道这VARIABLE=value会创建一个环境变量,并export VARIABLE=value使其可用于当前 shell 创建的进程。env显示当前的环境变量,但它们住在哪里?什么包含环境变量(或environment,就此而言)?

jor*_*anm 32

环境并不像看起来那么神奇。shell 将其存储在内存中并传递给execve()系统调用。子进程将它继承为一个名为 的数组指针environ。从execve联机帮助页:

概要

   #include <unistd.h>

   int execve(const char *filename, char *const argv[],
              char *const envp[]);
Run Code Online (Sandbox Code Playgroud)

argv是传递给新程序的参数字符串数组。
按照惯例,这些字符串中的第一个应该包含与正在执行的文件相关联的文件名。envp是一个字符串数组,通常采用 key=value 形式,它们作为环境传递给新程序。

environ(7)手册页还提供了一些见解:

概要

   extern char **environ;
Run Code Online (Sandbox Code Playgroud)

描述

该变量 environ指向一个指向字符串的指针数组,称为“环境”。此数组中的最后一个指针的值为NULL。(此变量必须在用户程序中声明,但在头文件<unistd.h>中声明,以防头文件来自 libc4 或 libc5,以及它们来自 glibc 且定义了 _GNU_SOURCE。)此字符串数组可用于通过 exec(3) 调用启动进程的进程。

这两个 GNU 联机帮助页都符合POSIX 规范

  • 请注意,这不是关于子进程(子进程继承其父进程的所有内存),而是执行的程序(在同一进程中),因此这是另一种通过 execve() 系统调用传递数据的方式(否则会擦除内存过程)。 (5认同)
  • +1 可能值得注意的是,`exec(3)` 系列的一些成员(即那些不匹配 exec*v 的成员)在幕后通过 **environ。 (4认同)

Bru*_*ger 19

你有一点点错误:SOME_NAME=value创建一个 shell 变量(在大多数 shell 中)。export SOME_NAME=value创建一个环境变量。不管是好是坏,大多数 Unix/Linux/*BSD shell 在访问环境变量和 shell 变量时使用相同的语法。

在更大的意义上,“环境”只是伴随程序执行的信息。在 C 程序中,您可能会通过getpid()调用找到进程 ID ,在 shell 程序中,您将使用变量访问:$$。进程 ID 只是程序环境的一部分。我相信术语“环境”来自一些更具理论性的计算机科学主题,例如对程序执行建模。程序执行模型有一个环境“其中包含变量及其值之间的关联”。

而后者,更强的定义是 Unix/Linux/*BSD shell 的“环境”:名称(“变量”)与其值之间的关联。对于大多数 Unix 风格的 shell,这些值都是字符串,尽管这不像过去那样严格。如今,Ksh、Zsh 和 Bash 都具有类型化变量。甚至可以导出 shell 函数定义。

使用与普通 shell 变量分开的环境涉及fork/exec启动所有 Unix 使用的新进程的方法。当您export使用名称/值对时,该名称/值对将出现在新的可执行文件的环境中,由 shell 通过execve(2)系统调用启动(通常在 之后fork(2),除非使用execshell 命令时)。

在 a 之后execve()main()new binary的函数有它的命令行参数,环境(存储为指向var=value字符串的以 NULL 结尾的指针数组,请参阅environ(7)手册页)。其他继承的状态包括ulimit设置、当前工作目录和execve()调用者没有设置 FD_CLOEXEC 的任何打开的文件描述符。tty 的当前状态(启用回显、原始模式等)也可以被视为新exec进程继承的执行状态的一部分。

简单命令(内建或shell函数除外)bash执行环境请参见手册中的描述。

Unix 环境至少与其他一些操作系统不同:VMS 的“词法”可以由子进程更改,并且该更改在父进程中可见。cd子进程中的VMS会影响父进程的工作目录。至少在某些情况下,我的记忆力可能让我失望。

一些环境变量是众所周知的$HOME$PATH$LD_LIBRARY_PATH和其他的。有些是给定编程系统的常规信息,因此父 shell 可以将大量特殊用途的信息传递给某个程序,例如特定的临时目录,或不会出现在ps -ef. 例如,简单的 CGI 程序通过环境变量从 Web 服务器继承了大量信息。

  • 更准确地说,环境变量不是继承的,而是从 shell 显式传递给它生成的程序。 (2认同)
  • @SamuelEdwinWard 你的`SOME_NAME=value command` 的行为与你的预期相反的原因是它是一种特殊的语法,意思是“将 SOME_NAME 添加到传递给命令的环境中,但不要以其他方式改变这个 shell 的变量”。 (2认同)

Dra*_*oan 7

最原始形式的环境变量只是一组名称/值对。如man 1 bash环境部分下的bash 手册页 ( ) 中所述:

   When  a  program  is invoked it is given an array of strings called the
   environment.   This  is  a  list  of  name-value  pairs,  of  the  form
   name=value.

   The  shell  provides  several  ways  to manipulate the environment.  On
   invocation, the shell scans its own environment and creates a parameter
   for  each name found, automatically marking it for export to child pro-
   cesses.  Executed commands inherit the  environment.
Run Code Online (Sandbox Code Playgroud)

实际上,它允许您定义从当前 shell 调用的程序共享或唯一的行为。例如,当使用crontabor 时,visudo您可以定义EDITOR环境变量来定义另一个编辑器,而不是您的系统默认使用的编辑器。对于诸如man查看您的PAGER环境以确定应该使用哪个寻呼程序来显示手册页输出的命令之类的内容,情况也是如此。

相当多的 unix 命令读取环境,并根据那里设置的内容改变它们的输出/处理/操作,具体取决于这些。有些是共享的,有些是程序独有的。大多数手册页都包含有关环境变量如何影响所描述程序的信息。

其他实际示例适用于在同一平台上安装了多个 Oracle 的系统。通过设置ORACLE_HOME,整个 oracle 命令套件(从您的PATH环境变量加载)然后从该顶级目录下提取设置、定义、映射和库。这同样适用于其他程序,例如带有JAVA_HOME环境变量的java 。

bash的本身具有许多环境变量可以改变的范围内从历史(事情的行为HISTSIZEHISTFILE等),屏幕尺寸(COLUMNS),制表符完成(FIGNOREGLOBIGNORE)语言环境和字符编码/解码(LANGLC_*),提示(PS1.. PS4),和依此类推(再次从 bash 手册页寻求知识)。

您还可以编写脚本/程序来使用您自己的自定义环境变量(以传递设置或更改功能)。