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结果可知两个进程为父子关系)去执行该命令。

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值