情景一:建立一个 shell 脚本 var1.sh,其内容为:
apple@ubuntu:~$ cat > var1.sh
#!/bin/bash
echo :$myvar:
然后在终端上执行变量赋值语句并用 echo
显示此变量
apple@ubuntu:~$ myvar=hello
apple@ubuntu:~$ echo $myvar
hello
但是当执行 var1.sh
脚本,想显示 myvar
变量时,情况却并非你所愿:
apple@ubuntu:~$ bash ./var1.sh
::
显然,var1.sh
并没有看到用户在终端中定义的 myvar
变量。可见,在终端中设置的变量,在运行的 shell
脚本中是无法看到的。
情景二:我们建立一个脚本 var2.sh,内容为:
apple@ubuntu:~$ cat -n var2.sh
1 #!/bin/bash
2 myvar=50
3 echo :$myvar:
此时,用户在终端设置 myvar
的值并显示此值,然后再运行 var2.sh
,看看结果吧:
apple@ubuntu:~$ myvar=100
apple@ubuntu:~$ echo $myvar
100
apple@ubuntu:~$ bash var2.sh
:50:
可见,终端中设置的值,在 shell 脚本中是无法改变的;而且,终端也无法改变 shell 脚本里面设置的变量的值。
总结:
在 Shell 工作机制中,存在一个 子shell
的概念,上面的两个情景展现的就是 子shell
的形象。子shell
是登录 shell 为了运行某个脚本程序而建立的一个全新的 shell,这个全新的 shell 只会使用自己的局部变量,对 父shell
(登录shell)的局部变量不屑一顾。而且,子shell
和 父shell
对对方的局部变量都不会有任何冒犯,井水不犯河水。
有些事情偏偏是需要 子shell
和 父shell
有所交互的,这就需要有一个变量是 子shell
和 父shell
都能看到和修改的。这时候,export
出现了,它可以“导出变量”。
情景三:建立一个新的 shell 脚本 var3.sh,其内容如下:
apple@ubuntu:~$ cat -n var3.sh
1 #!/bin/bash
2 echo mylocal=$mylocal
3 echo myglobal=$myglobal
在 var3.sh
脚本中,设置了两个变量,一个是 mylocal,表示局部变量,一个是 myglobal,表示全局变量。
在终端上给此两个变量赋值,然后执行脚本程序 var3.sh
,很明显,结果如你所愿,是空值:
apple@ubuntu:~$ mylocal=1
apple@ubuntu:~$ myglobal=2
apple@ubuntu:~$ bash var3.sh
mylocal=
myglobal=
我们针对 myglobal 执行 export
来导出变量,再看看结果:
apple@ubuntu:~$ export myglobal
apple@ubuntu:~$ bash var3.sh
mylocal=
myglobal=2
看,我们的脚本程序已经看到了 myglobal 的值了,看来 export 将 myglobal 导出,真是起到作用了。
总结:当使用 export
来导出一个变量时,当前 shell 就会将此变量放到“导出变量列表”中,一旦在某个时刻需要建立 子shell
时,就会将这个导出变量列表拷贝一份给 子shell
,这样 子shell
也就理所应当的看到了这些被导出的变量了。
情景四:看看整个过程:
apple@ubuntu:~$ export myglobal=10
apple@ubuntu:~$ cat -n var4.sh
1 #!/bin/bash
2 myglobal=33
3 echo myglobal=$myglobal
apple@ubuntu:~$ bash var4.sh
myglobal=33
apple@ubuntu:~$ echo $myglobal
10
可见,在 子shell
是无法改变 父shell
中的“导出变量列表”中变量的值的。子shell
只能修改自己手里的那份“导出变量列表”中变量的值。
总结:
子shell
是无法改变父shell
中的“导出变量列表”中变量的值的。- 变量一旦被导出,对所有后续执行的
子shell
,该变量都是导出变量。
全文总结:
- 没有导出的变量是局部变量,
子shell
是看不到的。 - 导出变量列表被复制给
子shell
,子shell
可以修改和存取它,但是这种修改父shell
看不到。 - 导出变量列表的上述特性对于直接产生的
子shell
生效,对于由子shell
产生的后继子shell
也是如此。 export
可以在变量赋值之后用,也可以在变量赋值之前用。