定义带或不带导出的变量

时间:2009-07-21 09:09:57

标签: linux bash shell

什么是export

有什么区别:

export name=value

name=value

14 个答案:

答案 0 :(得分:910)

export使变量可用于子流程。

即,

export name=value

表示变量名可用于从该shell进程运行的任何进程。如果您希望进程使用此变量,请使用export,然后从该shell运行该进程。

name=value

表示变量作用域仅限于shell,并且不可用于任何其他进程。你可以将它用于(比如)循环变量,临时变量等。

重要的是要注意,导出变量不会使父进程可用。也就是说,在生成的进程中指定和导出变量不会使其在启动它的过程中可用。

答案 1 :(得分:220)

说明其他答案的含义:

$ 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$ 

答案 2 :(得分:67)

其他人回答说,导出使变量可用于子壳,这是正确的,但仅仅是副作用。导出变量时,它会将该变量放在当前shell的环境中(即shell调用putenv(3)或setenv(3))。进程的环境在exec中继承,使变量在子shell中可见。

编辑(5年的观点):这是一个愚蠢的答案。 “导出”的目的是使变量“处于随后执行的命令的环境中”,无论这些命令是子单元还是子进程。一个简单的实现就是简单地将变量放在shell的环境中,但这样就无法实现export -p

答案 3 :(得分:53)

据说在产生子壳时没有必要以bash出口,而其他人则说完全相反。重要的是要注意子shell(由()``$()或循环创建的)和子进程(由名称调用的进程,例如文字{ {1}}出现在您的脚本中)。

  • shell 可以访问父级的所有变量,无论其导出状态如何。
  • 进程查看导出的变量。

这两个结构中常见的是两者都不能将变量传递回父shell。

bash

还有一个混乱的来源:有些人认为'分叉'子过程是那些看不到非导出变量的过程。通常fork()后面跟着exec()s,这就是为什么看起来fork()是寻找的东西,而实际上它是exec()。您可以先使用$ 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

请注意,我们这次没有看到$ noexport=noexport; export export=export; exec bash -c 'echo execd process: $noexport $export; execd=execd'; echo parent: $execd execd process: export 行,因为我们已经用parent:命令替换了父shell,所以没有什么可以执行该命令

答案 4 :(得分:28)

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。

答案 5 :(得分:10)

export将使变量可用于从当前shell派生的所有shell。

答案 6 :(得分:9)

应该注意,您可以导出变量,然后更改该值。变量的值已更改为子进程可用。为变量设置导出后,您必须export -n <var>删除该属性。

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset

答案 7 :(得分:7)

正如您可能已经知道的那样,UNIX允许进程拥有一组环境变量,这些变量是键/值对,键和值都是字符串。 操作系统负责分别为每个进程保留这些对。

程序可以通过此UNIX API访问其环境变量:

  • char *getenv(const char *name);
  • int setenv(const char *name, const char *value, int override);
  • int unsetenv(const char *name);

进程还从父进程继承环境变量。操作系统负责创建所有&#34; envars&#34;在创建子进程的那一刻。

除了其他shell之外,

Bash 能够根据用户请求设置其环境变量。这是export存在的原因。

export是一个Bash命令,用于为Bash设置环境变量。使用此命令设置的所有变量都将由此Bash将创建的所有进程继承。

更多关于Environment in Bash

Bash中的另一种变量是内部变量。由于Bash不仅仅是交互式shell,它实际上是一个脚本解释器,与任何其他解释器(例如Python)一样,它能够保留自己的变量集。应该提到的是,Bash(与Python不同)仅支持字符串变量。

定义Bash变量的表示法是name=value。这些变量保留在Bash中,与操作系统保存的环境变量无关。

有关Shell Parameters的更多信息(包括变量)

另外值得注意的是,根据Bash参考手册:

  

可以扩充任何简单命令或功能的环境   暂时通过为参数赋值添加前缀,如上所述   在Shell Parameters。这些赋值语句仅影响   该命令看到的环境。

总结一下:

  • export用于在操作系统中设置环境变量。此变量将可用于当前Bash过程创建的所有子进程。
  • Bash变量表示法(name = value)用于设置仅适用于当前bash进程的局部变量
  • 为另一个命令添加前缀的Bash变量表示法仅为该命令的范围创建环境变量。

答案 8 :(得分:5)

accepted answer暗示了这一点,但我想明确表示与shell builtins的连接:

如前所述,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

答案 9 :(得分:3)

这是另一个例子:

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}"'  

只有使用导出VARTEST,才能在sudo bash -c'...'中使用VARTEST的值!

有关更多示例,请参阅:

答案 10 :(得分:2)

只是为了显示环境中导出的变量(env)与不在环境中的非导出变量之间的区别:

如果我这样做:

$ MYNAME=Fred
$ export OURNAME=Jim

然后只有$ OURNAME出现在env中。变量$ MYNAME不在env。

$ env | grep NAME
OURNAME=Jim

但变量$ MYNAME确实存在于shell

$ echo $MYNAME
Fred

答案 11 :(得分:2)

UNIX的两位创建者Brian Kernighan和Rob Pike在他们的“UNIX编程环境”一书中解释了这一点。谷歌的标题,你会很容易找到一个PDF版本。

它们在3.6节中讨论shell变量,并专注于在该节末尾使用export命令:

  

如果要在子shell中访问变量的值,则应使用shell的export命令。 (您可能会想到为什么无法将变量的值从子shell导出到其父级。)

答案 12 :(得分:1)

虽然在讨论中没有明确提到,但是从bash中生成子shell时没有必要使用export,因为所有变量都被复制到子进程中。

答案 13 :(得分:0)

默认情况下,脚本中创建的变量仅对当前shell可用;子进程(子shell)将无法访问已设置或修改的值。允许子进程查看值,需要使用export命令。