source环境变量 - linux重置环境变量




用或不用导出定义一个变量 (10)

什么是export

有什么区别:

export name=value

name=value

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

它们在第3.6节中介绍shell变量,并着重介绍在该节末尾使用export命令:

当你想让一个变量的值在子shell中可用时,应该使用shell的export命令。 (你可能会想到为什么没有办法将变量的值从子shell导出到其父项)。


export NAME=value设置和变量的export NAME=value对子进程有意义。

NAME=value当前shell进程私有的临时或循环变量的NAME=value

更详细地说, 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将使变量对当前shell分支的所有shell都可用。


为了说明其他答案的内容:

al$ foo="Hello, World"
al$ echo $foo
Hello, World
al$ bar="Goodbye"
al$ export foo
al$ bash
bash-3.2$ echo $foo
Hello, World
bash-3.2$ echo $bar

bash-3.2$ 

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

如果我这样做:

$ MYNAME=Fred
$ export OURNAME=Jim

那么只有$ OURNAME出现在env中。 变量$ MYNAME不在env中。

$ env | grep NAME
OURNAME=Jim

但变量$ MYNAME确实存在于shell中

$ echo $MYNAME
Fred

应该指出的是,你可以导出一个变量,然后改变它的值。 变量的更改值可供子进程使用。 一旦为变量设置了export -n <var>您必须执行export -n <var>来移除该属性。

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

有人说,在产生子壳体时没有必要用bash来输出,而另一些人却说完全相反。 重要的是要注意子shell(由()``$()或循环创建的子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()紧跟着exec(),这就是为什么看起来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: line,因为我们已经用exec命令替换了父shell,所以没有什么可以执行该命令了。


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

程序可以通过这个UNIX API访问它的环境变量:

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

进程还从父进程继承环境变量。 操作系统负责创建子进程创建时所有“envars”的副本。

除其他shell外, Bash能够根据用户请求设置其环境变量。 这是export目的。

export是一个Bash命令来为Bash设置环境变量。 所有用这个命令设置的变量都会被Bash创建的所有进程继承。

更多关于Bash的环境

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

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

更多关于Shell参数 (包括变量)

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

Shell参数中所述,任何简单命令或函数的环境都可以通过在参数赋值前添加它来临时扩充。 这些赋值语句仅影响该命令看到的环境。

总结一下:

  • export用于在操作系统中设置环境变量。 此变量将可用于当前Bash进程创建的所有子进程。
  • Bash变量表示法(name = value)用于设置仅适用于当前bash进程的局部变量
  • 以另一个命令为前缀的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的值!

更多示例请参阅:


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





shell