Answers:
export
使该变量可用于子流程。
那是,
export name=value
表示变量名称可用于您从该Shell进程运行的任何进程。如果您希望进程使用此变量,请使用export
,然后从该Shell运行该进程。
name=value
表示变量作用域仅限于外壳程序,不适用于任何其他进程。您可以将其用于(例如)循环变量,临时变量等。
重要的是要注意,导出变量不会使其对父进程可用。也就是说,在生成的进程中指定和导出变量不会使其在启动它的进程中可用。
name=value command
确实在子流程中使变量可用command
。
其他人回答说,导出使变量可用于子外壳,这是正确的,但仅是副作用。导出变量时,它将把该变量放在当前shell的环境中(即shell调用putenv(3)
或setenv(3)
)。
进程的环境跨exec继承,使该变量在子shell中可见。
编辑(从5年的角度来看):这是一个愚蠢的答案。“导出”的目的是使变量“处于随后执行的命令的环境中”,无论这些命令是子shell还是子进程。天真的实现方式是将变量简单地放在shell的环境中,但这将使其无法实现export -p
。
bash
,export确实确实将变量添加到了当前shell的环境中,但是情况并非如此dash
。在我看来,将变量添加到当前shell的环境中是实现的语义的最简单方法export
,但是这种行为不是强制性的。
dash
与此有关。原始海报专门问了一下bash
。
bash
带有标签,但同样适用于任何本恩-壳变体。过于具体和提供仅适用于自己的答案bash
是一个大恶魔。
bash
是外壳的jQuery。
export makes the variable available to subshells, and that is correct
这是一个非常混乱的术语用法。子shell不需要export
继承变量。子流程可以。
据说在生成子壳时不必导出bash,而其他人则表示完全相反。需要注意的子shell之间的区别是很重要的(那些被创建()
,``
,$()
或回路)和子(即通过名称调用,如流程文字bash
出现在你的脚本)。
这两种构造的共同点是,它们都不会将变量传递回父外壳。
$ noexport=noexport; export export=export; (echo subshell: $noexport $export; subshell=subshell); bash -c 'echo subprocess: $noexport $export; subprocess=subprocess'; echo parent: $subshell $subprocess
subshell: noexport export
subprocess: export
parent:
还有一个混乱的根源:有人认为“分叉”子流程是那些看不到未导出变量的子流程。通常fork()之后紧跟exec(),这就是为什么fork()似乎是要寻找的东西,而实际上是exec()。您可以先运行命令,而无需先使用fork()exec
,该方法启动的进程也将无法访问未导出的变量:
$ noexport=noexport; export export=export; exec bash -c 'echo execd process: $noexport $export; execd=execd'; echo parent: $execd
execd process: export
请注意,这次我们看不到该parent:
行,因为我们已经用exec
命令替换了父shell ,所以没有什么可以执行该命令了。
&
)还会创建一个子外壳。
var=asdf bash -c 'echo $var'
还是var=asdf exec bash -c 'echo $var'
?输出为asdf
。所述;
如果放置在变量定义后,使差。请问是什么解释?看起来var
(no ;
)以某种方式考虑生成子进程,因为原始shell与它无关。echo $var
如果在第二行执行,则不打印任何内容。但是一个内衬var=asdf bash -c 'echo $var'; echo $var
给asdf\nasdf
。
export NAME=value
用于对子流程有意义的设置和变量。
NAME=value
用于当前shell进程专用的临时或循环变量。
更详细地,export
在环境中标记变量名称,该环境将在创建后复制到子流程及其子流程。不会从子流程复制任何名称或值。
一个常见的错误是在等号周围放置一个空格:
$ export FOO = "bar"
bash: export: `=': not a valid identifier
B
子进程仅看到导出的变量():
$ A="Alice"; export B="Bob"; echo "echo A is \$A. B is \$B" | bash
A is . B is Bob
子流程中的更改不会更改主外壳:
$ export B="Bob"; echo 'B="Banana"' | bash; echo $B
Bob
创建子流程时,标记为导出的变量具有复制的值:
$ export B="Bob"; echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash &
[1] 3306
$ B="Banana"; echo '(sleep 30; echo "Subprocess 2 has B=$B")' | bash
Subprocess 1 has B=Bob
Subprocess 2 has B=Banana
[1]+ Done echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash
仅导出的变量成为环境(man environ
)的一部分:
$ ALICE="Alice"; export BOB="Bob"; env | grep "ALICE\|BOB"
BOB=Bob
因此,现在应该像夏天的阳光一样清晰!感谢Brain Agnew,alexp和William Prusell。
应该注意的是,您可以导出变量,然后再更改值。变量的更改值将可用于子进程。为变量设置导出后,您必须export -n <var>
删除该属性。
$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset
您可能已经知道,UNIX允许进程具有一组环境变量,这些环境变量是键/值对,键和值都是字符串。操作系统负责为每个进程分别保留这些对。
程序可以通过以下UNIX API访问其环境变量:
char *getenv(const char *name);
int setenv(const char *name, const char *value, int override);
int unsetenv(const char *name);
进程还从父进程继承环境变量。操作系统负责在创建子进程时创建所有“ envar”的副本。
Bash和其他shell一样,能够根据用户要求设置其环境变量。这就是export
存在的目的。
export
是Bash命令,用于为Bash设置环境变量。使用此命令设置的所有变量将被此Bash创建的所有进程继承。
有关Bash环境的更多信息
Bash中的另一种变量是内部变量。由于Bash不仅是交互式外壳,因此实际上是脚本解释器,与其他解释器(例如Python)一样,它能够保留自己的变量集。应该提到的是,Bash(与Python不同)仅支持字符串变量。
定义Bash变量的符号为name=value
。这些变量保留在Bash中,与操作系统保留的环境变量无关。
有关Shell参数(包括变量)的更多信息
同样值得注意的是,根据Bash参考手册:
如Shell Parameters中所述,可以通过在其前面添加参数分配来临时扩展任何简单命令或功能的环境。这些赋值语句仅影响该命令看到的环境。
总结一下:
export
用于在操作系统中设置环境变量。此后,此变量将可用于当前Bash进程创建的所有子进程。这是另一个例子:
VARTEST="value of VARTEST"
#export VARTEST="value of VARTEST"
sudo env | grep -i vartest
sudo echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}"
sudo bash -c 'echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}"'
只有通过使用export VARTEST才能在sudo bash -c'...'中获得VARTEST的值!
有关更多示例,请参见:
bash-hackers.org/wiki/doku.php/scripting/processtree
尽管在讨论中没有明确提及,但是从bash内部生成子shell时不必使用export,因为所有变量都已复制到子进程中。
export name=value
不能移植。根据您的实际需求,尝试name=value; export name
一种便携式解决方案。