Linux 需要环境变量
Linux need for environment variables
我一直在阅读 Linux 中有关环境变量的内容。我能理解如何设置/读取它们。
我想问的是概念上为什么要将环境变量添加到 Linux 中?是否有没有它们就无法满足的系统要求?
在我看来,出于某种原因似乎需要一个额外的配置层,一些与实际流程功能分离的东西。我想知道更多有经验的开发者的意见。
变量用于编写脚本和程序管理。例如,您可以编写一个脚本问候语并在其中指定变量$USER,它将显示当前用户的名称。程序可以访问变量,变量也可以用于它们的工作。例如,Linux 上 GUI 中的程序 运行,您可以指定 X 服务器,它们将通过该服务器显示其数据。
环境变量对 Linux 上的 运行 程序非常有用。我们通常需要在程序中读取一些系统配置,环境变量是允许我们访问这些配置的好地方。
环境变量[此处:env]满足无法[方便]以其他方式处理的需求。
因此,我们提出以下问题:程序如何获取每次调用时可能会更改的配置数据?
我们可以将所有内容作为程序参数传递:pgmA PATH=... DISPLAY=...
但是程序必须解析它。而且,当 pgmA 调用 pgmB 时,它必须将此数据作为参数传递。换句话说,every 程序必须知道 every 变量,即使它对变量本身没有用。
我们可以将所有内容都放在配置文件中,但每次调用都需要一个不同的配置文件。将这些文件放在哪里,如何保证运行它们具有唯一的名称,how/when在不再需要它们时删除它们[即使面对中止的程序],变得棘手。
对于 env 变量,它们驻留在程序中内核在执行程序时创建的特殊内存部分,以及 std execvp
等。阿尔。 (在一些内核帮助下)将愉快地传递这个环境,而大多数程序无需执行任何操作。
但是,pgmA 可以自由地在 fork
之后和 execvp
之前的 child 中为 pgmB 更改某些内容(例如,向 [=15= 添加一个额外的目录) ]).换句话说,env 在 parent 和 child 之间是分层的(例如,更改 child 而不是 更改 parent——这是一件好事)
env 还允许传递低阶程序所需的东西。考虑 pgmA fork/exec
s pgmB 又 fork/exec
s pgmC。 pgmA/pgmB 只是普通程序 [并且不使用 any env 变量本身]。但是 pgmC 是 xterm
,它需要知道要在什么 X11 显示器上输出。它从 DISPLAY
env var.
中获取
假设我们 运行 从主 GUI 控制台在 window 终端程序中执行上述操作。 DISPLAY
[可能] 是 :0
。 xterm
出现在本地屏幕上。现在考虑我们从 ssh 登录做同样的事情。这里 DISPLAY
将是 w.x.y.z:0
,xterm
将在本地计算机上执行,但会在远程系统的屏幕上显示自己。
环境的另一个主要用途是为没有[合法]访问argv
或配置文件的东西提供配置。即,共享库 [.so
s]。这里有两个例子:
内核执行ELF程序时,会将可执行文件映射到内存中。然后它会在 "ELF loader" 的特殊部分中查找,在 Linux 下是(例如)/lib64/ld-linux-x86-64.so.2
。内核将加载程序映射到应用程序内存中,并将程序的控制权交给加载程序。反过来,加载程序解析对程序所需的共享库的引用并加载,然后 t运行 将控制权交给程序的 start 函数。
ldd
程序将打印出给定程序使用的共享库。但是,它实际上并没有这样做。它设置一个环境变量,然后执行目标程序。 ELF 加载器看到这个变量,而不是执行程序,它只是加载它,打印共享库的名称。 ELF 加载器有许多会影响其操作的环境变量(例如,参见 man ld.so
)。
另一个使用该环境的库是 glibc
。当 glibc
遇到致命错误时,例如双重释放指针或堆损坏,它会打印一条错误消息。通常,glibc
会将此输出到 /dev/tty
。有时,这是不可取的,我们宁愿将错误消息转到 stderr
[我们打开错误日志文件的位置]。为了让 glibc
实现我们的愿望,我们在调用程序之前将环境变量 LIBC_FATAL_STDERR_
设置为 1
。
此配置内容 可以 由 WinX registry-like 接口处理,数据可以驻留在 per-process 内核内存中。但是,这对内核 和 程序来说很麻烦。内核不想在 [珍贵的] 内核地址 space 中携带这种可变大小的信息。应用程序不希望使用系统调用的开销来获取它。
大多数 C 程序员将他们的 main
函数写成 int main(int argc,char **argv)
,但对于实际传递的函数,它可以[更恰当地]写成 int main(int argc,char **argv,char **envp)
。 envp
实际上指向一个定义:
char *environ[] = {
"DISPLAY=:0",
"PATH=/usr/bin:/bin",
...
NULL
};
libc 函数 getenv
、setenv
、putenv
对全局进行操作。但是,当将指针传递给 execvpe
时,您可以完全指定一个 different env array,填充任何你想要的东西。因此,您可以直接操作数组 [以及环境]。
历史脚注: 环境变量并非特定于 Linux。它们没有 添加 --它们一直存在 [在 Linux] 中。而且,自从 ea最谎言的化身,就像 argc/argv
。这可以追溯到 [至少] 贝尔实验室的 Unix V7 [并且可能更早]。
我一直在阅读 Linux 中有关环境变量的内容。我能理解如何设置/读取它们。
我想问的是概念上为什么要将环境变量添加到 Linux 中?是否有没有它们就无法满足的系统要求?
在我看来,出于某种原因似乎需要一个额外的配置层,一些与实际流程功能分离的东西。我想知道更多有经验的开发者的意见。
变量用于编写脚本和程序管理。例如,您可以编写一个脚本问候语并在其中指定变量$USER,它将显示当前用户的名称。程序可以访问变量,变量也可以用于它们的工作。例如,Linux 上 GUI 中的程序 运行,您可以指定 X 服务器,它们将通过该服务器显示其数据。
环境变量对 Linux 上的 运行 程序非常有用。我们通常需要在程序中读取一些系统配置,环境变量是允许我们访问这些配置的好地方。
环境变量[此处:env]满足无法[方便]以其他方式处理的需求。
因此,我们提出以下问题:程序如何获取每次调用时可能会更改的配置数据?
我们可以将所有内容作为程序参数传递:pgmA PATH=... DISPLAY=...
但是程序必须解析它。而且,当 pgmA 调用 pgmB 时,它必须将此数据作为参数传递。换句话说,every 程序必须知道 every 变量,即使它对变量本身没有用。
我们可以将所有内容都放在配置文件中,但每次调用都需要一个不同的配置文件。将这些文件放在哪里,如何保证运行它们具有唯一的名称,how/when在不再需要它们时删除它们[即使面对中止的程序],变得棘手。
对于 env 变量,它们驻留在程序中内核在执行程序时创建的特殊内存部分,以及 std execvp
等。阿尔。 (在一些内核帮助下)将愉快地传递这个环境,而大多数程序无需执行任何操作。
但是,pgmA 可以自由地在 fork
之后和 execvp
之前的 child 中为 pgmB 更改某些内容(例如,向 [=15= 添加一个额外的目录) ]).换句话说,env 在 parent 和 child 之间是分层的(例如,更改 child 而不是 更改 parent——这是一件好事)
env 还允许传递低阶程序所需的东西。考虑 pgmA fork/exec
s pgmB 又 fork/exec
s pgmC。 pgmA/pgmB 只是普通程序 [并且不使用 any env 变量本身]。但是 pgmC 是 xterm
,它需要知道要在什么 X11 显示器上输出。它从 DISPLAY
env var.
假设我们 运行 从主 GUI 控制台在 window 终端程序中执行上述操作。 DISPLAY
[可能] 是 :0
。 xterm
出现在本地屏幕上。现在考虑我们从 ssh 登录做同样的事情。这里 DISPLAY
将是 w.x.y.z:0
,xterm
将在本地计算机上执行,但会在远程系统的屏幕上显示自己。
环境的另一个主要用途是为没有[合法]访问argv
或配置文件的东西提供配置。即,共享库 [.so
s]。这里有两个例子:
内核执行ELF程序时,会将可执行文件映射到内存中。然后它会在 "ELF loader" 的特殊部分中查找,在 Linux 下是(例如)/lib64/ld-linux-x86-64.so.2
。内核将加载程序映射到应用程序内存中,并将程序的控制权交给加载程序。反过来,加载程序解析对程序所需的共享库的引用并加载,然后 t运行 将控制权交给程序的 start 函数。
ldd
程序将打印出给定程序使用的共享库。但是,它实际上并没有这样做。它设置一个环境变量,然后执行目标程序。 ELF 加载器看到这个变量,而不是执行程序,它只是加载它,打印共享库的名称。 ELF 加载器有许多会影响其操作的环境变量(例如,参见 man ld.so
)。
另一个使用该环境的库是 glibc
。当 glibc
遇到致命错误时,例如双重释放指针或堆损坏,它会打印一条错误消息。通常,glibc
会将此输出到 /dev/tty
。有时,这是不可取的,我们宁愿将错误消息转到 stderr
[我们打开错误日志文件的位置]。为了让 glibc
实现我们的愿望,我们在调用程序之前将环境变量 LIBC_FATAL_STDERR_
设置为 1
。
此配置内容 可以 由 WinX registry-like 接口处理,数据可以驻留在 per-process 内核内存中。但是,这对内核 和 程序来说很麻烦。内核不想在 [珍贵的] 内核地址 space 中携带这种可变大小的信息。应用程序不希望使用系统调用的开销来获取它。
大多数 C 程序员将他们的 main
函数写成 int main(int argc,char **argv)
,但对于实际传递的函数,它可以[更恰当地]写成 int main(int argc,char **argv,char **envp)
。 envp
实际上指向一个定义:
char *environ[] = {
"DISPLAY=:0",
"PATH=/usr/bin:/bin",
...
NULL
};
libc 函数 getenv
、setenv
、putenv
对全局进行操作。但是,当将指针传递给 execvpe
时,您可以完全指定一个 different env array,填充任何你想要的东西。因此,您可以直接操作数组 [以及环境]。
历史脚注: 环境变量并非特定于 Linux。它们没有 添加 --它们一直存在 [在 Linux] 中。而且,自从 ea最谎言的化身,就像 argc/argv
。这可以追溯到 [至少] 贝尔实验室的 Unix V7 [并且可能更早]。