13.1.9 变量的作用域

变量的作用域又叫“命名空间”,表示变量(identifier,标识符)的上下文。相同的变量可以在多个命名空间中定义,并且彼此之间互不干涉,所以在一个新的命名空间中可以自定义任何变量,因为所定义的变量都只在各自的命名空间中。就像A班有个小明,B班也有个小明一样,虽然他们都叫小明(对应于变量名),但是由于所在的班级不一样(对应于命名空间),所以这不会造成混乱。但是如果同一个班级中有两个小明,就必须用类似于“大小明”、“小小明”这样的命名来区分他们。

在Linux系统中,不同进程ID的Shell默认为一个不同的命名空间。下面的例子展示了同名变量在两个不同命名空间中是互不影响的。


  1. #Namespace01.sh

  2. 中声明了VAR_01=100

  3. [root@localhost ~]# cat Namespace01.sh

  4. #!/bin/bash

  5. VAR_01=100

  6. echo VAR_01 in $0:$VAR_01

  7. #

  8. 此处调用Namespace02.sh

  9. bash Namespace02.sh

  10. #Namespace02.sh

  11. 中声明了VAR_01=200

  12. [root@localhost ~]# cat Namespace02.sh

  13. #!/bin/bash

  14. VAR_01=200

  15. echo VAR_01 in $0:$VAR_01

  16. #

  17. 执行Namespace01.sh

  18. ,看到同名变量VAR_01

  19. 在不同的脚本中的值是不一样的

  20. [root@localhost ~]# bash Namespace01.sh

  21. VAR_01 in Namespace01.sh:100

  22. VAR_01 in Namespace02.sh:200


Shell变量的作用域是在本Shell内,属于本Shell的全局变量,也就是从定义该变量的地方开始到Shell结束,或到主动使用unset删除了该变量的地方为止。在变量的作用域内,该变量都是可见的,在函数内对变量也是可以访问、可修改的,这和C语言极为不同。


  1. [root@localhost ~]# cat Namespace03.sh

  2. #!/bin/bash

  3. VAR_02=100

  4. #

  5. 定义函数ch_var()

  6. ,该函数中重新定义VAR_02

  7. 并赋值为200

  8. function ch_var() {

  9. VAR_02=200

  10. }

  11. echo "Before function VAR_02:$VAR_02"

  12. #

  13. 调用函数

  14. ch_var

  15. echo "After function VAR_02:$VAR_02"

  16. #Namespace03.sh

  17. 执行结果

  18. [root@localhost ~]# bash Namespace03.sh

  19. Brfore function VAR_02:100

  20. After function VAR_02:200


同样的代码用C实现后,VAR_02的值并没有受到函数内部同名变量的影响。


  1. [root@localhost ~]# cat Namespace03.c

  2. #include <stdio.h>

  3. int VAR_02=100;

  4. void ch_var(void) {

  5. int VAR_02=200;

  6. }

  7. int main() {

  8. printf("Before function VAR_02: %d\n", VAR_02);

  9. ch_var();

  10. printf("After function VAR_02: %d\n", VAR_02);

  11. }

  12. #

  13. 执行结果

  14. [root@localhost ~]# ./a.out

  15. Before function VAR_02: 100

  16. After function VAR_02: 100


存在这种差别的原因在于,Shell默认以Shell的进程ID作为一个命名空间,所以即便是在函数中声明变量,该变量也会在全局生效。而C语言会对函数内的变量单独创建命名空间,这样就不会影响全局定义的同名变量。

Shell的这种特性在一般情况下是没有太大问题的,但有时确实可能会给程序的开发造成麻烦,特别是当脚本实现了模块化的开发后,不同的人共同维护同一个脚本中不同功能的代码时,很可能大家都会用到比较常见的类似于i、j、k这样的临时变量(特别是在函数内部,使用这样的变量尤为常见),这无疑会造成问题。为了解决这种问题,在函数内部声明的临时变量需要用local指定其为只在函数内生效的“局部变量”,这样这些变量将只存在于局部的命名空间内,从而不会对全局变量有影响。下面按照这种方式对Namespace03.sh进行修改,在函数内部使用local声明变量VAR_02,再次执行然后查看效果。


  1. [root@localhost ~]# cat Namespace03.sh

  2. #!/bin/bash

  3. VAR_02=100

  4. function ch_var() {

  5. local VAR_02=200 #

  6. 此处使用local

  7. 声明变量

  8. }

  9. echo "Before function VAR_02:$VAR_02"

  10. ch_var

  11. echo "After function VAR_02:$VAR_02"

  12. #

  13. 修改后的Namespace03.sh

  14. 执行结果

  15. [root@localhost ~]# bash Namespace03.sh

  16. Before function VAR_02:100

  17. After function VAR_02:100


从执行结果可以看到,在函数体内使用local关键字声明了和全局变量同名的局部变量后,对该变量的操作只会影响局部变量,而不会影响与之同名的全局变量。