陈斌彬的技术博客

Stay foolish,stay hungry

Shell 局部变量和导出变量

情景一:建立一个 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,该变量都是导出变量。

全文总结:

  1. 没有导出的变量是局部变量,子shell 是看不到的。
  2. 导出变量列表被复制给 子shell子shell 可以修改和存取它,但是这种修改 父shell 看不到。
  3. 导出变量列表的上述特性对于直接产生的 子shell 生效,对于由 子shell 产生的后继 子shell也是如此。
  4. export 可以在变量赋值之后用,也可以在变量赋值之前用。