变量的作用域
每个Shell进程有自己的作用域。直接在当前进程中定义的变量可以被称为局部变量(Local Variables),局部变量不可被其他Shell进程访问到。
在日常开发中,会出现shell脚本互相调用的情况。当我们在一个Shell里面运行另一个shell脚本时,该shell会fork出一个新进程,启动另外一个命令解释器去运行这个脚本。新进程可以被称为子shell,之前的shell是个父shell。而子shell也是无法获取到父shell中的局部变量的。
#!/bin/bash
name="father"
sh ./son.sh
#!/bin/bash
echo "my father's name is ${name}"
# output: my father's name is
这时候,要引入环境变量(Environment Variables)的概念。环境变量可用于shell进程的任何子进程。
export命令
export 是bash shell 内置的命令。使用export命令将环境变量导出给任何新创建的子shell。
子shell获得变量的一个拷贝,在子shell中修改环境变量,不会影响父shell中该环境变量的值,也不会影响到其他的子shell。
通常,环境变量是大写的。来看一个例子:
#!/bin/bash
NAME="father"
export NAME
sh ./son.sh
echo "my name is ${NAME}"
# output: my name is father
#!/bin/bash
echo "my father's name is ${NAME}"
# output: my father's name is father
NAME="son"
通过export命令导出的环境变量是有局限性的:
- 只对当前的shell进程及其子进程有效,如果最顶层的父进程关闭,那么环境变量就消失了,子进程也无法使用。变量是临时的。
- 变量可以向下导出到子shell,但是不能导出到父shell。
source命令
source命令也是bash shell 内置的命令,可用于加载任何功能文件到当前的shell脚本或命令行中。它从给定的文件中读取并执行命令,然后返回。
source命令也被称为点命令,执行source fiilename
和. filename
的效果是一样的。但是一般会建议使用source,因为点有可能和路径中使用的点混淆,容易引起一些失误。
来看一个例子:
#!/bin/bash
NAME="father"
source ./son.sh
echo "[father] my name is ${NAME}"
# output: [father] my name is son
echo "my son's name is ${SON_NAME}"
# output: my son's name is son
#!/bin/bash
echo "my father's name is ${NAME}"
# output: my father's name is father
NAME="son"
SON_NAME="son"
如果我们使用source而不是sh去执行文件,用不着使用export,父shell就可以获得子shell中的环境变量,子shell也可以修改父shell中环境变量的值。
总结
export和source的区别
export和source是完全不同的两个命令,export用于导出环境变量,source用于执行文件。
souce filename和sh filename执行文件的区别
- sh filename 会fork出一个子shell,在子shell中执行脚本里面的语句。子shell可以将父shell中导出的环境变量拷贝一份供自己使用,但是无法修改环境变量,也无法将环境变量导出给父shell。
- source filename 会读取脚本中的语句,并依次在当前的shell进程中执行,并不会建立子shell。脚本中所有的新建,修改变量的语句都会在当前的shell中生效。