013-在 Shell 脚本中调用另一个 Shell 脚本的三种方式,终端打开调用sh
如下:
- fork: 如果脚本有执行权限的话,
path/to/foo.sh
。如果没有,sh path/to/foo.sh
。 - exec:
exec path/to/foo.sh
- source:
source path/to/foo.sh
1、fork
fork 是最普通的, 就是直接在脚本里面用 path/to/foo.sh 来调用
foo.sh 这个脚本,比如如果是 foo.sh 在当前目录下,就是 ./foo.sh。运行的时候 terminal 会新开一个子 Shell 执行脚本 foo.sh,子 Shell 执行的时候, 父 Shell 还在。子 Shell 执行完毕后返回父 Shell。 子 Shell 从父 Shell 继承环境变量,但是子 Shell 中的环境变量不会带回父 Shell。
2、exec
exec
与 fork
不同,不需要新开一个子 Shell 来执行被调用的脚本. 被调用的脚本与父脚本在同一个 Shell 内执行。但是使用 exec
调用一个新脚本以后, 父脚本中 exec
行之后的内容就不会再执行了。这是 exec
和 source
的区别.
3、source
与 fork
的区别是不新开一个子 Shell 来执行被调用的脚本,而是在同一个 Shell 中执行. 所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中进行获取和使用。
测试
脚本1、父脚本
#!/usr/bin/env bash A=1 echo "执行调用之前进程Id exec/source/fork: PID for 1.sh = $$" export A echo "In 1.sh: variable A=$A" case $1 in --exec) echo -e "==> using exec…\n" exec ./2.sh ;; --source) echo -e "==> using source…\n" . ./2.sh ;; *) echo -e "==> using fork by default…\n" ./2.sh ;; esac echo "执行调用之后进程Id exec/source/fork: PID for 1.sh = $$" echo -e "父脚本1.sh: variable A=$A\n"
脚本2、子脚本
#!/usr/bin/env bash echo "子脚本2PID for 2.sh = $$" echo "In 2.sh get variable A=$A from 1.sh" A=2 export A echo -e "子脚本2.sh默认A=2: variable A=$A\n"
测试一、fork方式,直接调用
$ ./1.sh 执行调用之前进程Id exec/source/fork: PID for 1.sh = 71145 In 1.sh: variable A=1 ==> using fork by default… 子脚本2PID for 2.sh = 71146 In 2.sh get variable A=1 from 1.sh 子脚本2.sh默认A=2: variable A=2 执行调用之后进程Id exec/source/fork: PID for 1.sh = 71145 In 1.sh: variable A=1
fork
方式可以看出,两个脚本都执行了,运行顺序为1-2-1,从两者的PID值(1.sh PID=71145, 2.sh PID=71146),可以看出,两个脚本是分成两个进程运行的。
测试二、exec方式:./1.sh exec
$ ./1.sh exec 执行调用之前进程Id exec/source/fork: PID for 1.sh = 71288 In 1.sh: variable A=1 ==> using exec… 子脚本2PID for 2.sh = 71288 In 2.sh get variable A=1 from 1.sh 子脚本2.sh默认A=2: variable A=2
exec
方式运行的结果是,2.sh 执行完成后,不再回到 1.sh。运行顺序为 1-2。从pid值看,两者是在同一进程 PID=71288 中运行的。
测试三、source方式:./1.sh source
$ ./1.sh source 执行调用之前进程Id exec/source/fork: PID for 1.sh = 71319 In 1.sh: variable A=1 ==> using source… 子脚本2PID for 2.sh = 71319 In 2.sh get variable A=1 from 1.sh 子脚本2.sh默认A=2: variable A=2 执行调用之后进程Id exec/source/fork: PID for 1.sh = 71319 父脚本1.sh: variable A=2
source方式的结果是两者在同一进程里运行。该方式相当于把两个脚本先合并再运行。
对比
Command | 进程 | 变量 | Explanation |
---|---|---|---|
fork | 父子不同进程 | 子继承父变量,子不能传递给父 |
新开一个子 Shell 执行,当子进程执行完毕后会返回父进程,但是父进程的环境变量不会因子进程的改变而改变。 子 Shell 可以从父 Shell 继承环境变量,但是子 Shell 中的环境变量不会带回给父 Shell。 |
exec | 同进程 | 子继承父,子进程结束 | 在同一个 Shell 内执行,但是父脚本中 exec 行之后的内容就不会再执行了,相当于父脚本执行exec进入子脚本后不再回到父脚本。 |
source | 同进程 | 子继承父变量,子同时回传给父 | 在同一个 Shell 中执行,在被调用的脚本中声明的变量和环境变量, 都可以在主脚本中进行获取和使用,相当于合并两个脚本在执行。 |
脚本地址:https://github.com/bjlhx15/shell.git 下的test/invokesh
示例一,打开终端调用一个shell
可以在: ~/.bash_profile
内加入:sh /etc/show_hostip.sh
这个内show_hostip.sh写扩展脚本