#!/bin/bash
exepath=/home/ydzhang/dnfs
prog=dnfs-server
export status=0 # 0 denotes stopped, 1 denotes started.
killproc()
{
ps -e | grep $1 | {
while read pid tty time cmd
do
echo "Killing $cmd(pid = $pid) ..."
kill -9 $pid
done
}
}
start()
{
echo starting $prog ...
if [ $status -eq 0 ]
then
$exepath/$prog & # run program in background
status=1
fi
rq_status
}
stop()
{
echo $status
echo stopping $prog ...
if [ $status -eq 1 ]
then
killproc $prog
status=0
fi
rq_status
}
restart()
{
stop
start
}
rq_status()
{
if [ $status -eq 0 ]
then
echo $prog is stopped
else
echo $prog is started
fi
}
gt_status()
{
ps -e | grep $prog | {
while read pid tty time cmd
do
if [ $cmd = $prog ]
then
status=1
break
fi
done
}
}
gt_status
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
status)
rq_status
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
esac
以上脚本用于启动,关闭,重新启动某个程序,类似于 /etc/init.d 中的脚本。
最开始没有使用 gt_status ,即在执行脚本前检查该程序的进程是否存在,每次 stop 的时候都会出问题,因脚本执行完毕后, status 的赋值生效,但 stop 是重新执行一次脚本,故 status 的默认值为 0 ,故 stop 什么都不做。
于是加上 gt_status ,检查程序是否已经运行,问题依然存在,即使已有进程在运行, status 的值仍没有被设置为 1 。 考虑到肯定是跟变量的性质有关,到网上查了一下,发现由于 gt_status 中使用了管道操作, while 语句的操作都是在子 shell 中完成,此时的 status 为子 shell 下的新变量,而不是脚本开始处的 status 变量;即使 export 变量 status ,子 shell 对 status 的修改对父 shell 也不可见。
父 shell 与子 shell 间的变量遵守以下原则:
1. 没有导出的变量是局部变量,子 shell 是看不到的。
2. 导出变量列表被赋值给子 shell ,子 shell 可以修改和存取它,但是这种修改对父 shell 不可见。
3. 导出变量列表的上述特性对于直接产生的子 shell 生效,对于由子 shell 产生的后继子 shell 也是如此。
4. export 可以在变量赋值之后用,也可以在变量赋值之前用。
对于本例中的需求,可通过将 ps –e | grep $prog 的结果先定向到一个临时文件中,然后从临时文件中读取,判断 cmd 是否为 $prog ,然后设置 status 的值,此时的值由父 shell 设置,故接下来的 case 语句中能读到 case 的新值。