最近想写个shell脚本,实现一个监测功能,然后退出
遇到几个问题:
1、主shell内部包含管道命令时,会创建其他子shell,无法退出(子shell有循环)
2、shell变量赋值和“宏定义”的问题
以下原代码,test是假设的一个系统调用
#!/bin/sh
heart()
{
while true
do
printf '\n'
sleep 1
done
}
watch()
{
(heart) | test | while read line
do
case "$line" in
*'exit'*)
exit
;;
...
done
}
watch
上面会执行完,exit后,ps发现还有两个进程存在
分别是heart和test的。
一番百度后,了解了shell脚本中,管道“|” 的命令会放在子shell中执行,就是另外开一个shell跑。
我需要在退出的时候, 把这个shell起的子shell也一起退出。
有什么好办法呢?
看到有办法说$$返回的是子shell pid,但是我这里有多个子shell,只返回了一个pid也不行
目前我用了一个办法:脚本查找指定进程pid,杀死
所以有了下面的优化版代码,增加exitsh
#!/bin/sh
#pid
pid=$(pgrep -f test)
sh_pid=$(pgrep -f $0)
heart()
{
while true
do
printf '\n'
sleep 1
done
}
exitsh()
{
echo -e "pid:$pid $sh_pid\n\n"
kill -9 $pid
kill -9 $sh_pid
exit
}
watch()
{
(heart) | test | while read line
do
case "$line" in
*'exit'*)
exitsh
;;
...
done
}
watch
看起来没问题,但是结果发现,却杀不死,一看打印pid是空的
???
哪里出问题了?百度都是这样跑的啊。。。
最后发现。。。。
pid=$(pgrep -f test)
这句放在文件前面,已经赋值了,并不是宏定义,而是变量赋值,前面一开始的时候test还没有运行,所以是空的
这里插入一句:$()和`` 功能一样是一样的
那么我要做类似宏定义怎么办?
又看了一番[单引号,双引号,反引号的区别],参考别人的文章(https://www.jb51.net/article/33495.htm)
再把脚本改一下
#!/bin/sh
#pid
pid="pgrep -f test"
sh_pid="pgrep -f $0"
heart()
{
while true
do
printf '\n'
sleep 1
done
}
exitsh()
{
echo -e "pid:$($pid) $($sh_pid)\n\n"
kill -9 $($pid)
kill -9 $($sh_pid)
exit
}
watch()
{
(heart) | test | while read line
do
case "$line" in
*'exit'*)
exitsh
;;
...
done
}
watch
这下终于可以了,主shell里面就可以在任意位置调用 ( ( (pid),就可以得到pid的值了
shell脚本命令异常捕捉
用 $? 取得上一条命令的返回值并判断。
Linux中0表示True,非0表示False。
因为脚本使用了多个管道命令组成
如果其中一个命令被杀掉了,导致脚本无法正常执行
此时,脚本里面需要类似errno的机制来处理
#!/bin/sh
#pid
pid="pgrep -f test"
sh_pid="pgrep -f $0"
heart()
{
while true
do
printf '\n'
sleep 1
done
}
exitsh()
{
echo -e "pid:$($pid) $($sh_pid)\n\n"
kill -9 $($pid)
kill -9 $($sh_pid)
exit
}
watch()
{
(heart) | test | while read line
//可以判断上述命令结果
ret=$?
if [ ret -ne 0 ];then
echo "cmd err"
exitsh
fi
do
case "$line" in
*'exit'*)
exitsh
;;
...
done
}
watch
学习了