shell脚本中执行命令误区
原理
Linux操作系统下shell脚本是开发项目中是比较常用的。shell脚本是如何被Linux系统所调用执行的呢,首先我们以ps命令为例,来解释一下shell脚本是如何被系统执行的。
命令:ps -o pid,ppid,pgid,sid,comm
其中:pid:自身进程id,ppid:父进程id,pgid:所属进程组id,sid:所属会话id,comm:命令。
在Linux系统下执行程序结果如下:
由上图可以看到,ps的父进程为bash,这正是我们所希望的。bash和ps命令两者位于同一会话和前台进程(1982)。不同的终端连接系统时bash所属会话和进程组都不一样,因此每个终端有自身的所属会话和进程组。
Shell调用本质其实是由shell(该系统的shell类型为bash)调用fork()函数创建一个进程,由该创建的子进程去调用一种exec函数去执行另一个程序。当子进程调用一种exec函数时,该子进程的执行的程序完全替换为新进程,因为调用exec函数并不创建新进程,所有前后进程的进程ID并不改变。exec程序只是用一个全新程序替换了当前进程的代码段,数据段、堆和栈。举个比较形象的例子,就好像一栋大楼里面刚开始是腾讯公司在里面办公,后来倒闭了,里面搬进了阿里巴巴公司,尽管大楼内的部署跟执行的任务已经改变,但这栋大楼还是之前的大楼。
在Linux系统下shell如果在一个管道中执行三个进程我们可以检验一下bash使用的进程控制方式。如下:
由上实验我们可知,bash使用的进程控制方式是:在执行每个命令调用时,都会由bash自身创建一个进程,然后由创建的子进程去调用exec函数去执行调用命令,而且bash创建的所有进程与bash同属一个会话(session id : 3983);而所有的子进程同属一个进程组(gpid:7151),该进程组ID为进程ps命令所属进程ID。如下:
实例
笔者在项目开发中遇到过这种情况,需要在后台跑一个shell脚本程序,名称为test_lijd.sh。该脚本的任务是定时获取系统信息,当然这并不重要。在该进程执行前需检测有没有同名的进程(名称为test_lijd.sh)已经在运行,如果有,则立刻退出,没有则起该进程去完成任务。
代码 lijd_test.sh 如下:
#!/bin/bash
########################
#filename : lijd_test.sh
#auth : lijd
#data : 2018-12-27
########################
main()
{
ps aux | grep lijd_test.sh | grep -v grep | wc -l 1>log.txt
ret1=`cat log.txt`
ret2=`ps aux | grep lijd_test.sh | grep -v grep | wc -l`
echo "ret1 = "$ret1", ret2 = "$ret2
}
main
运行结果如下:
执行同一个命令,将结果标准输出的结果写入log.txt文件中跟直接赋值给变量得到的值不一样!!!为什么?
我们进一步写测试代码验证,打印出执行结果分析。代码如下:
#!/bin/bash
########################
#filename : lijd_test.sh
#auth : lijd
#data : 2018-12-27
########################
main()
{
# 打印当前进程ID
echo "this process ID : "$$
echo "=======================方式一执行==============================="
# 方式一执行
ps aux | grep lijd_test.sh | grep -v grep 1>log.txt
ret1=`cat log.txt`
echo $ret1
echo "=======================方式二执行 1=============================="
# 方式二执行 1
ret2=`ps aux | grep lijd_test.sh | grep -v grep`
echo $ret2
echo "=======================方式二执行 2=============================="
# 方式二执行 2
ret3=`ps axjf | grep lijd_test.sh | grep -v grep`
echo $ret3
echo "======================================================"
}
main
执行结果如下:
由上面运行结果可知:该脚本运行时,如果进程内部以方式一执行ps命令,该进程不会生成子进程去执行该命令。如果进程内部以方式二执行ps命令,该进程会fork()出子进程(由方式二执行2结果可知两个进程为父子关系)去执行该命令。
更多推荐
所有评论(0)