提示:以下是介绍为什么写这篇文章:
-
如何再shell脚本中调用其他脚本?
-
顺序调用会保证脚本的顺序执行吗?
一、在 Shell 脚本中调用另一个 Shell 脚本的三种方式
先来说一下主要以下有几种方式:
-
fork: 如果脚本有执行权限的话,path/to/foo.sh。如果没有,sh path/to/foo.sh。
-
exec: exec path/to/foo.sh
-
source: source path/to/foo.sh
1.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。
1.2 exec
exec
与 fork
不同,不需要新开一个子 Shell
来执行被调用的脚本. 被调用的脚本与父脚本在同一个 Shell 内执行。但是使用 exec
调用一个新脚本以后, 父脚本中 exec
行之后的内容就不会再执行了。这是 exec 和 source
的区别.
1.3 source
与 fork 的区别是不新开一个子 Shell 来执行被调用的脚本,而是在同一个 Shell 中执行. 所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中进行获取和使用。
其实从命名上可以感知到其中的细微区别,下面通过两个脚本来体会三种调用方式的不同: 第一个脚本,命名为script1.sh:
#!/usr/bin/env bash
A=1
echo "before 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 "after exec/source/fork: PID for 1.sh = $$"
echo -e "In 1.sh: variable A=$A\n"
第二个脚本,我们命名为 2.sh:
#!/usr/bin/env bash
echo "PID for 2.sh = $$"
echo "In 2.sh get variable A=$A from 1.sh"
A=2
export A
echo -e "In 2.sh: variable A=$A\n"
注:这两个脚本中的参数 $$
用于返回脚本的 PID
, 也就是进程 ID
。这个例子是想通过显示 PID
判断两个脚本是分开执行还是同一进程里执行,也就是是否有新开子 Shell
。当执行完脚本 2.sh 后,脚本 1.sh 后面的内容是否还执行。
$ ./1.sh
PID for 1.sh before exec/source/fork:5845
1.sh: $A is B
using fork by default…
PID for 2.sh: 5242
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:5845
1.sh: $A is B
fork
方式可以看出,两个脚本都执行了,运行顺序为1-2-1
,从两者的PID值,可以看出,两个脚本是分成两个进程运行的。
$ ./1.sh – exec
PID for 1.sh before exec/source/fork:5562
1.sh: $A is B
using exec…
PID for 2.sh: 5562
2.sh get $A=B from 1.sh
2.sh: $A is C
exec
方式运行的结果是,2
执行完成后,不再回到1
。运行顺序为1-2
。从pid
值看,两者是在同一进程中运行的。
$ ./1.sh source
PID for 1.sh before exec/source/fork:5156
1.sh: $A is B
using source…
PID for 2.sh: 5156
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:5156
1.sh: $A is C
source
方式的结果是两者在同一进程里运行。该方式相当于把两个脚本先合并再运行。
二. 等待.sh脚本仅在另一个脚本完成后才能运行?
2.1 &&连接器
只需使用&&连接器(即复合命令):
./script1.sh && ./script2.sh
但是请注意,只有script1.sh 即第一个脚本退出代码为0(即没有错误)时,才会执行第二个脚本。
2.2 ;连接器
如果要执行序列,无论第一个脚本的结果如何,只需执行以下操作
./script1.sh ; ./script2.sh
您可以测试两个连接器的行为:
$ true && echo aa
aa
$ false && echo aa
$ false ; echo aa
aa
总结
除了exec
之外,其他都可以顺序执行,只是如果对环境变量有要求的话,就要分辨使用fork
还是source