在运行shell脚本时候,有三种方式来调用外部的脚本,exec(exec script.sh)方式、source(source script.sh)方式、fork(./script.sh)方式。
fork方式
通常情况下在系统中通过相对路径或绝对路径执行一个命令时,都会由父进程开启一个子进程,当子进程结束后再返回父进程,这种行为过程就叫fork。当脚本中正常调用一个外部命令或其他脚本时,都会fork一个子shell进程,我们的命令会运行在这个子shell中。
subshell.sh
#!/bin/bash
#使用&在后台进程开启子shell
count=0
for i in {1..254}
do
ping -c1 -i0.2 -WL 192.168.43.$i >/dev/null && let count++ &
done
echo $count
for_test.sh
#!/bin/bash
sleep 5
#绝对路径或相对路径调用外部脚本时会fork子进程
/home/minger/share/shell/subshell.sh
这个脚本在执行的过程中会打开一个终端窗口,反复执行pstree可以获得如下的进程树信息。可以看出,我们脚本调用一个外部命令时(sleep)时,系统会fork一个子shell,sleep命令是在子shell中执行的。
当脚本通过相对路径或者绝对路径调用外部其他脚本时,会fork一个子进程,并且subshell.sh脚本中命令被触发执行时也会再次fork子进程。
可以用pstree查看:
使用fork方式开启的子进程是父进程的一个副本,因此会自动单向继承父进程的环境,如环境变量、资源权限、内存中的数据、信号等等。但是,父进程无法继承子进程环境。
exec方式
使用exec方式调用其他命令或脚本时,系统不会开启子进程,而是使用新的程序替换当前的shell环境,因为当前shell被替换了,所以当exec调用的程序结束后,当前环境会被关闭。
exec执行命令流程图:
上面的图中,通过exec时执行ls命令,一个是使用用echo命令让屏幕回显一个字符串信息,最后一个是cd 命令,用于切换目录。但是,第一命令使用exec调用ls,系统使用ls命令替换当前的脚本,整个进程就变成了一个ls命令,当ls命令结束后进程也就结束了。
下面来看看例子:
#!/bin/bash
exec ls
echo "test"
cd /shell
这里有个特例,当exec后面的参数文件重定向时,不会替换当前的shell环境,脚本后续其他命令也不会受到任何影响。
source方式
使用source或者“.”来调用外部脚本,不会产生新的进程,继承当前shell环境变量,而且被调用的脚本运行结束后,它拥有的环境变量和声明变量会被当前shell保留,类似将调用脚本的内容复制过来直接执行。执行完毕后原主shell继续运行。
下面来看个简单例子:
tmp.sh
#!/bin/bash
env="Minger"
source.sh
#!/bin/bash
source /tmp/tmp.sh
echo "hi,$env"
ls /
在上面的source.sh脚本中使用source命令加载/tmp/tmp.sh脚本,source命令会在不开启shell情况下,将tmp.sh中的所有命令加载当前shell环境中,类似tmp.sh文件中的所有命令编写在source.sh文件中的一样。
欢迎关注公众号【程序猿编码】,添加本人微信号(17865354792),回复:领取学习资料。或者回复:进入技术交流群。网盘资料有如下: