使用Linux系统时经常需要监控程序运行情况,比如最近我遇到了一个情况就是一个控制程序偶尔会在运行中退出,在这种情况下我需要立即重启该程序。最后在谢枫同学脚本的基础上完成了重启脚本。
目前遇见了两种情况: 一是程序是一个可执行文件; 二是使用python打开的多个程序。两种的区别在哪里呢?对于前者,它的进程名字由路径名字和程序名字组成,比如:
我有个程序是qt生成的可执行文件,名字为Manipulator,路径是/home/mk90/Documents/qt_exercise/build-Manipulator-Desktop-Debug
输入命令**(命令的含义在下面再解释)**
ps -ef | grep Manipulator|grep -v grep
结果是
mk90 20604 18895 0 19:11 ? 00:00:00 /home/mk90/Documents/qt_exercise/build-Manipulator-Desktop-Debug/Manipulator
对于后者,他的进程名字既有python字眼,又有程序名字,但是没有路径。比如有一个test.py程序,使用
python test.py
打开程序,然后在打开一个新的终端输入:
ps -ef | grep python|grep -v grep
或者
ps -ef | grep test.py|grep -v grep
都能得到结果:
mk90 3345 3307 0 21:12 pts/1 00:00:00 python test.py
如果使用上面的那条指令,在有多个python程序运行时,显示的进程名字都以python开头,如:
这时候就需要判断是哪一个python进程了。
还以上面的Manipulator程序为例,其shell脚本为:
restart.sh
#! /bin/bash
while true
do
monitor=`ps -ef | grep Manipulator | grep -v grep | wc -l `
if [ $monitor -eq 0 ]
then
echo "Manipulator program is not running, restart Manipulator"
./home/mk90/Documents/qt_exercise/build-Manipulator-Desktop-Debug/Manipulator
else
echo "Manipulator program is running"
fi
sleep 5
done
脚本解释:
#! /bin/bash :其中#!为Sha-bang符号,是shell脚本的起始符号,告诉Linux系统这个文件需要指定解释器; /bin/bash 指明了解释器所在的路径,对于一般的shell脚本而言,解释器可以是bash,也可以是sh。
while … do … done : shell脚本里while循环的用法
monitor=`ps -ef | grep Manipulator | grep -v grep | wc -l `
上面这一句的作用是把后面指令运行的结果赋值给monitor,注意等号“=”前后不要有空格表示赋值,如果有空格则表示判断是否相等。
注意符号 ` 不是单引号 ’ ,位置是数字键1左边的那个键,上面是~,下面是它,它叫反引号或者又叫后引号,这个引号包围的为命令,可以执行包围的命令,并将执行的结果赋值给变量。
ps -ef 指令中ps的意思是process status,即进程状态, -ef 是ps命令的选项,表示以详细格式显示所有进程内容。
竖线 “ | ” 称为管道符号,是Linux系统一个很强大的功能,表示把前一个命令的输出结果传递给后一个命令处理。
grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。后面的Manipulator是要搜索的关键字。
grep -v grep : 其中 -v 是grep命令的选项,表示反向选择,这几个字符表示在前面搜索结果的基础上去除掉带有grep关键字的内容。 因为使用 ”grep+关键字“ 命令搜索时会有一个grep本身的进程,而且带有搜索的关键字,这个就是要排除自身搜索的影响。
wc -l : wc命令统计指定文件中的字节数、字数、行数,并将统计结果显示输出。选项 ”-l “ 表示统计行数。
以详细格式查看所有进程,从中选出具有关键字 Manipulator 的进程,但是排除掉用于查找的grep自身进程,对于满足上面条件的结果,统计其行数,也就是看有几个带有Manipulator关键字的进程,将统计的结果赋值给变量monitor 。
if…then…else…fi : shell脚本里面 if 语句的用法, fi 符号与 if 符号成对使用,表示 if 语句的结束。
if [ $monitor -eq 0 ] : if 语句的判断用 test 或者 “[ ]” ,符号” $“ 表示取变量的值, -eq表示等于, -gt大于, -lt小于, -ge大于等于,-le小于等于。
echo :用于输出显示。
./home/mk90/Documents/qt_exercise/build-Manipulator-Desktop-Debug/Manipulator
用于运行Manipulator程序。
sleep 5 : 休眠5秒钟。
因为知道自己想要监控的程序的具体名字,所以对于这一类程序的监控也可以用上面的方法,但是这一类情况也让我们思索另一种方法进行监控。
在我的 /home/mk90/Documents/restart_pro 文件夹里有 test.py 和 test2.py 两个python程序,现在我要看这两个程序是否已经打开,如果没有就打开它们。
multi_restart.sh
#!/bin/bash
declare -a Array
while(true)
do
echo -e `date`
Array[0]=0
Array[1]=1
Array[0]=`pgrep python | sed -n 1p | awk '{print $1}'`
Array[1]=`pgrep python | sed -n 2p | awk '{print $1}'`
if [ ${Array[0]} ]
then
echo -e "test.py is running!"
else
echo -e "test.py is not running and restart it"
gnome-terminal -x bash -c "python /home/mk90/Documents/restart_pro/test.py; exec bash"
fi
if [ ${Array[1]} ]
then
echo -e "test2.py is running!"
else
echo -e "test2.py is not running and restart it"
gnome-terminal -x bash -c "python /home/mk90/Documents/restart_pro/test2.py; exec bash"
fi
#clear
echo -e "\n"
sleep 1
done
里面有很多内容在前面的例子里讲过了,需要解释的有以下几点:
declare -a Array : 表示声明了一个数组 Array
echo -e date
: 用来打印日期和时间,参数 -e表示激活转义字符,详细可以参考
https://www.cnblogs.com/karl-python/p/9261920.html
pgrep python | sed -n 1p | awk '{print $1}’
这句指令包含的内容较多
pgrep 是通过程序的名字来查询进程的工具;
sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换、删除、新增、选取等特定工作,详细用法可以参考
https://blog.csdn.net/zhushuai1221/article/details/53114178
sed -n 1p : 的作用就是对前面查找的结果,读取第一行,同样 sed -n 2p 就是读取第二行 ;
awk '{print $1}’ : awk命令通常是将所列出的行,根据条件打印出某一列或几列,这里就是打印以空格为分隔符的第一列(其实也只有一列,因为pgrep命令只输出进程的pid号;
那么
Array[0]=`pgrep python | sed -n 1p | awk '{print $1}'`
Array[1]=`pgrep python | sed -n 2p | awk '{print $1}'`
两条指令的意思就是,查看名为python的进程,把查到的第一个进程的pid号赋值给Array[0],把第二个赋值给Array[1];
后面的判断就是只要有进程pid号,说明进程存在,否则进程不存在。
gnome-terminal -x bash -c "python /home/mk90/Documents/restart_pro/test2.py; exec bash"
这句代码的意思就是打开一个新的终端,执行命令 ”python /home/mk90/Documents/restart_pro/test2.py“,执行完毕后该终端保持存在不关闭。
gnome-terminal 是终端的一种,Ubuntu系统的终端就是这种版本, 参数 -x 表示后面出现的都当做命令执行,并且只执行一次;
bash 是防止终端立即关闭,如果输入:
gnome-terminal -x ls
终端执行后会一闪就关闭,甚至看不到执行的效果;
"-c"选项使shell解释器从一个字符串中而不是从一个文件中读取并执行shell命令;
exec bash 使终端运行命令后仍然存在。
缺陷:
用这种方法有一个缺陷,就是需要知道会有几个python程序以及它们的的顺序;如果有两个的话,操作第二个是正常的,可以重启,但是如果第一个程序死了,也会重启第二个程序!!!因为第一个进程中断之后,系统实时监测,第二个进程变成了最前面的也是唯一的python进程,那么它认为第一个程序还在运行,而第二个程序停止了,所以会重启第二个程序。
这种方法仅作为思路参考吧。。。。。。