【发布时间】:2010-11-12 14:04:32
【问题描述】:
export 是干什么用的?
有什么区别:
export name=value
和
name=value
【问题讨论】:
-
另外注意
export name=value不可移植。根据您的具体需求,尝试name=value; export name以获得便携式解决方案。
export 是干什么用的?
有什么区别:
export name=value
和
name=value
【问题讨论】:
export name=value 不可移植。根据您的具体需求,尝试name=value; export name 以获得便携式解决方案。
其他人回答说 export 使变量可用于子shell,这是正确的,但只是副作用。当您导出一个变量时,它会将这个变量放入当前 shell 的环境中(即 shell 调用 putenv(3) 或 setenv(3))。
进程的环境跨 exec 继承,使变量在子 shell 中可见。
编辑(以 5 年的视角):这是一个愚蠢的答案。 “导出”的目的是使变量“在随后执行的命令的环境中”,无论这些命令是子外壳还是子进程。一个幼稚的实现是简单地将变量放在 shell 的环境中,但这将导致无法实现 export -p。
【讨论】:
bash 中,export 确实将变量添加到当前shell 的环境中,但dash 并非如此。在我看来,将变量添加到当前 shell 的环境中是实现export 语义的最简单方法,但这种行为不是强制性的。
dash 与此有什么关系。原发帖人专门询问bash。
bash,但同样适用于任何 bourne-shell 变体。过于具体并提供仅适用于 bash 的答案是大恶。
bash 是shell的jQuery。
export makes the variable available to subshells, and that is correct 这是一个非常混乱的术语用法。子shell 不需要export 来继承变量。子流程可以。
据说生成子shell时不必在bash中导出,而其他人则完全相反。重要的是要注意子shell(由()、``、$() 或循环创建的那些)和子进程(按名称调用的进程,例如出现在脚本中的文字 bash )。
这两种结构的共同点是两者都不能将变量传回父 shell。
$ 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()s 之后紧跟 exec()s,这就是为什么看起来 fork() 是要寻找的东西,而实际上它是 exec()。您可以使用exec 命令在没有 fork() 的情况下运行命令,并且由此方法启动的进程也将无法访问未导出的变量:
$ noexport=noexport; export export=export; exec bash -c 'echo execd process: $noexport $export; execd=execd'; echo parent: $execd
execd process: export
请注意,这次我们没有看到 parent: 行,因为我们已经用 exec 命令替换了父 shell,所以没有任何东西可以执行该命令。
【讨论】:
&) 也会创建一个子 shell。
var=asdf bash -c 'echo $var' 或var=asdf exec bash -c 'echo $var' 怎么样?输出为asdf。 ; 放在变量定义之后会有所不同。会有什么解释?看起来var(没有;)以某种方式涉及产生的子进程,因为原始shell与它无关。 echo $var 如果在第二行执行,则不打印任何内容。但是一排 var=asdf bash -c 'echo $var'; echo $var 给 asdf\nasdf。
var=value command 在命令command 的持续时间内将变量var 设置为值value。这有点类似于env 命令的作用。
为了说明其他答案的意思:
$ foo="Hello, World"
$ echo $foo
Hello, World
$ bar="Goodbye"
$ export foo
$ bash
bash-3.2$ echo $foo
Hello, World
bash-3.2$ echo $bar
bash-3.2$
【讨论】:
al$ foobar="Whatever" bash
accepted answer 暗示了这一点,但我想明确说明与 shell 内置函数的连接:
如前所述,export 将使 shell 和子级都可以使用一个变量。如果export 不 被使用,该变量将只在shell 中可用,并且只有shell builtins 可以访问它。
也就是说,
tango=3
env | grep tango # prints nothing, since env is a child process
set | grep tango # prints tango=3 - "type set" shows `set` is a shell builtin
【讨论】:
需要注意的是,您可以导出一个变量,然后再更改该值。变量的更改值将可用于子进程。为变量设置导出后,您必须执行 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 的两位创建者 Brian Kernighan 和 Rob Pike 在他们的《UNIX 编程环境》一书中对此进行了解释。谷歌搜索标题,你会很容易找到一个 pdf 版本。
它们在第 3.6 节中介绍了 shell 变量,并重点介绍了该节末尾的 export 命令的使用:
当你想让一个变量的值在子 shell 中可访问时,应该使用 shell 的 export 命令。 (你可能会想为什么无法将变量的值从子 shell 导出到其父 shell)。
【讨论】:
您可能已经知道,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 不仅仅是交互式 shell,它实际上是一个脚本解释器,与任何其他解释器(例如 Python)一样,它能够保留自己的一组变量。需要指出的是,Bash(与 Python 不同)仅支持字符串变量。
定义 Bash 变量的符号是name=value。这些变量留在 Bash 内部,与操作系统保存的环境变量无关。
更多关于Shell Parameters(包括变量)
另外值得注意的是,根据 Bash 参考手册:
可以扩充任何简单命令或功能的环境 暂时通过在其前面加上参数分配,如所述 在Shell Parameters。这些赋值语句只影响 该命令看到的环境。
总结一下:
export 用于在操作系统中设置环境变量。此变量将可用于当前 Bash 进程创建的所有子进程。【讨论】:
A="string" 这样的公共变量实际上与A[0]="string" 相同。事实上,在说出A="string" 之后,您可以使用A[1]="string2"、A+=(string3 string4 "string 5 is longer") 然后echo "${A[@]}" 将更多字符串连接到1 字符串数组以打印它们。请注意,它需要像将数组提供给 printf 命令这样的操作,以便在字符串之间获得某种分隔符,因为默认值是空格,而 string5 包含空格。
export a b; a=this; b[0]=that; env | grep ^[ab] 并不相同。在 C/C++/Java 中,float 和 double 在某些 情况下可以互换,但它们仍然是不同的类型。
默认情况下,在脚本中创建的变量只对当前 shell 可用;子进程(子外壳)将无法访问已设置或修改的值。允许子进程查看值,需要使用导出命令。
【讨论】:
只是为了显示在环境 (env) 中的导出变量和不在环境中的非导出变量之间的区别:
如果我这样做:
$ MYNAME=Fred
$ export OURNAME=Jim
然后只有 $OURNAME 出现在环境中。变量 $MYNAME 不在环境中。
$ env | grep NAME
OURNAME=Jim
但变量 $MYNAME 确实存在于 shell 中
$ echo $MYNAME
Fred
【讨论】:
export 使变量可用于子进程。
也就是说,
export name=value
表示变量名称可用于您从该 shell 进程运行的任何进程。如果您希望某个进程使用此变量,请使用export,然后从该 shell 运行该进程。
name=value
表示变量范围仅限于 shell,不能用于任何其他进程。您可以将其用于(例如)循环变量、临时变量等。
请务必注意,导出变量不会使其对父进程可用。也就是说,在衍生进程中指定和导出变量不会使其在启动它的进程中可用。
【讨论】:
name=value command确实使变量在子进程command中可用。
虽然在讨论中没有明确提到,但从 bash 内部生成子 shell 时没有必要使用 export,因为所有变量都被复制到子进程中。
【讨论】:
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
子进程的变化不会改变主shell:
$ 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。
【讨论】:
这是另一个例子:
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
【讨论】:
export 将使该变量可用于从当前 shell 派生的所有 shell。
【讨论】: