Ame*_*ina 94 shell process environment-variables
我在这里读到,export在 shell中的目的是使变量可用于从 shell 启动的子进程。
但是,我也看到了这里,并在这里说的“进程从它们的父(这开始它们的进程)继承他们的环境。”
如果是这种情况,我们为什么需要export?我错过了什么?
默认情况下,shell 变量不是环境的一部分吗?有什么不同?
koj*_*iro 106
您的假设是 shell 变量在 environment 中。这是不正确的。该export命令定义了在环境中的名称。因此:
a=1 b=2
export b
Run Code Online (Sandbox Code Playgroud)
导致当前shell知道$a扩展为 1 和$b2,但子进程不会知道任何信息,a因为它不是环境的一部分(即使在当前 shell 中)。
一些有用的工具:
set: 用于查看当前 shell 的参数,是否导出set -k:在环境中设置分配的参数。考虑f() { set -k; env; }; f a=1set -a: 告诉 shell 将设置的任何名称放入环境中。就像export在每次作业之前放置一样。对.env文件有用,如set -a; . .env; set +a.export: 告诉 shell 在环境中放置一个名称。导出和分配是两个完全不同的操作。env: 作为外部命令,env只能告诉你继承的环境,因此,它对健全性检查很有用。env -i:用于在启动子进程之前清除环境。替代方案export:
name=val command # 命令之前的赋值将该名称导出到命令。declare/local -x name # 导出名称,当您想避免将名称暴露给外部作用域时,在 shell 函数中特别有用。set -a # 导出每个后续分配。那么为什么 shell 需要有自己的变量和不同的环境呢?我确定有一些历史原因,但我认为主要原因是范围界定。该环境适用于子进程,但您可以在 shell 中执行许多操作,而无需分叉子进程。假设你循环:
for i in {0..50}; do
somecommand
done
Run Code Online (Sandbox Code Playgroud)
为什么要somecommand通过include 来浪费内存i,让它的环境比它需要的更大?如果您在 shell 中选择的变量名称恰好意味着程序意外的内容怎么办?(我个人最喜欢的包括DEBUG和VERBOSE。这些名称随处可见,很少使用命名空间。)
有时要了解 Unix 行为,您必须查看系统调用,这是与内核和操作系统交互的基本 API。在这里,我们查看exec调用系列,这是 shell 在创建子进程时使用的。这是手册页中exec(3)的引用(强调我的):
的
execle()和execvpe()功能允许呼叫者通过参数envp指定执行程序的环境。envp 参数是一个指向空终止字符串的指针数组,必须以空指针终止。其他函数从调用进程中的外部变量environ 获取新进程映像的环境。
所以export somename在shell中写就相当于把名字复制到environC中的全局字典中。但是赋值somename而不导出就像在C中赋值一样,而不是将它复制到environ变量中。
And*_*ese 29
shell 变量和环境变量之间存在差异。如果你定义一个 shell 变量而不对其进行exporting,它不会被添加到进程环境中,因此不会被继承到它的子进程。
使用export您告诉 shell 将 shell 变量添加到环境中。您可以使用printenv(它只是将其环境打印到stdout,因为它是一个子进程,您可以看到exporting 变量的效果)来测试它:
#!/bin/sh
MYVAR="my cool variable"
echo "Without export:"
printenv | grep MYVAR
echo "With export:"
export MYVAR
printenv | grep MYVAR
Run Code Online (Sandbox Code Playgroud)
变量一旦导出,就是环境的一部分。PATH在 shell 本身中导出,而自定义变量可以根据需要导出。使用一些设置代码:
$ cat subshell.sh
#!/usr/bin/env bash
declare | grep -e '^PATH=' -e '^foo='
Run Code Online (Sandbox Code Playgroud)
相比
$ cat test.sh
#!/usr/bin/env bash
export PATH=/bin
export foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test.sh
PATH=/bin
foo=bar
PATH=/bin
foo=bar
Run Code Online (Sandbox Code Playgroud)
和
$ cat test2.sh
#!/usr/bin/env bash
PATH=/bin
foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test2.sh
PATH=/bin
foo=bar
PATH=/bin
Run Code Online (Sandbox Code Playgroud)
由于foo不是由 shell 导出的,也test2.sh从未导出过,因此它不是subshell.sh上次运行环境的一部分。