当你调用
source
或
.
(其中一个是另一个的别名。
source
命令不是POSIX标准 - 类似于bashism),你将一个shell脚本
加载并执行到当前的shell进程中。因此,你可以:
- 读取在被引用脚本中设置的变量,
- 使用在其中定义的函数。
- 甚至执行分支和/或子进程,如果脚本这样做的话。
当你调用
sh
时,你启动了一个
fork(子进程或
子进程),它运行一个新的
/bin/sh
会话(通常是一个符号链接到
bash
)。在这种情况下,子脚本设置的环境变量将在子脚本终止时被丢弃。
注意: sh
可能是一个符号链接到另一个 shell。
实用示例
例如,如果你想以特定的方式改变当前工作目录,你不能这样做
$ cat <<eof >myCd2Doc.sh
#!/bin/sh
cd /usr/share/doc
eof
$ chmod +x myCd2Doc.sh
这个不会做你期望的事情:
$ cd /tmp
$ pwd
/tmp
$ ~/myCd2Doc.sh
$ pwd
/tmp
因为
当前工作目录是环境的一部分,
myCd2Doc.sh
将在一个
子shell中运行。
但是:
$ source ~/myCd2Doc.sh
$ pwd
/usr/share/doc
同样,声明一个函数的方式也是一样的:
$ cat >~/myCd2Doc.source <<eof
# Shell source file
myCd2Doc() {
cd /usr/share/doc
}
eof
$ . ~/myCd2Doc.source
$ cd /tmp
$ pwd
/tmp
$ myCd2Doc
$ pwd
/usr/share/doc
快来看看mycd
函数吧!(带有基于关联数组的bash自动补全)。
执行级别$SHLVL
$ cd /tmp
printf %b '\43\41/bin/bash\necho This is level \44SHLVL.\n' >qlvl.sh
$ bash qlvl.sh
This is level 2.
$ source qlvl.sh
This is level 1.
递归(当一个脚本从自身运行时)
$ cat <<"eoqlvl2" >qlvl2.sh
export startLevel recursionLimit=5
echo This is level $SHLVL started:${startLevel:=$SHLVL}.
(( SHLVL < recursionLimit )) && ./qlvl2.sh
eoqlvl2
$ chmod +x qlvl2.sh
$ ./qlvl2.sh
This is level 2 started:2.
This is level 3 started:2.
This is level 4 started:2.
This is level 5 started:2.
$ source qlv2.sh
This is level 1 started:1.
This is level 2 started:1.
This is level 3 started:1.
This is level 4 started:1.
This is level 5 started:1.
再进一点
$ sed '$a ps --sid $SID fw' qlvl.sh >qlvl3.sh
$ chmod +x qlvl3.sh
$ export SID
$ read SID < <(ps ho sid $$)
$ echo $SID $$
8983 8983
(当前的
PID(
$$
==
进程ID)与
SID(
会话ID)是相同的标识符。但这并不总是正确的。)
$ ./qlvl3.sh
This is level 2.
PID TTY STAT TIME COMMAND
8983 pts/10 Ss 0:00 /bin/bash
10266 pts/10 S+ 0:00 \_ /bin/bash ./qlvl3.sh
10267 pts/10 R+ 0:00 \_ ps --sid 8983 fw
$ . qlvl3.sh
This is level 1.
PID TTY STAT TIME COMMAND
8983 pts/10 Ss 0:00 /bin/bash
10428 pts/10 R+ 0:00 \_ ps --sid 8983 fw
Dot(点)是source(源)的别名。所以这两个命令之间唯一的区别是斜杠(slash)被空格(space)替代。
还有一个最后的测试:
$ printf %b '\43\41/bin/bash\necho Ending this.\nsle' \
'ep 1;exit 0\n' >finalTest.sh
$ bash finalTest.sh
Ending this.
$ source finalTest.sh
Ending this.
你可能会注意到这两种语法之间的行为有所不同。;-)
sh
和bash
之间的区别。 - tripleee