checkpid、__pids_var_run和__pids_pidof函数
pid文件的路径可能为/var/run/$base.pid文件($base表示进程名的basename),也可能是自定义的路径,例如mysql的pid可以自定义为/mysql/data/mysql01.pid。但无论哪种情况,functions中的__pids_var_run函数都可以处理。
pid文件中可能有多行,表示多实例。
每个进程都必有一个pid,但并不一定都记录在pid文件中,例如线程的pid。但无论如何,在/proc/目录下,一定会有pid号命名的目录,只要有对应pid号的目录,就表示该进程已经在运行。函数checkpid专门检测给定的pid值在/proc下是否有对应的目录存在。
为了获取进程名的pid值,此处函数__pids_pidof使用的是pidof命令。该命令专门设计用来在脚本中取给定进程的pid。它的”-o”选项用于忽略某些进程号,在脚本中应用时常被忽略的是调用pidof的shell的PID,当前shell的PID以及父shell的pid。总之,该函数的目的就是为了获取合理无误的进程pid。
以下是函数checkpid、__pids_var_run和__pids_pidof的定义语句。
# Check if any of $pid (could be plural) are running
checkpid() {
local i
for i in $* ; do # 检测/proc目录下是否存在给定的进程目录
[ -d "/proc/$i" ] && return 0
done
return 1
}
# __proc_pids {program} [pidfile]
# Set $pid to pids from /var/run* for {program}. $pid should be declared
# local in the caller.
# Returns LSB exit code for the 'status' action.
__pids_var_run() { # 通过检测pid判断程序是否已在运行
local base=${1##*/} # 获取进程名的basename
local pid_file=${2:-/var/run/$base.pid} # 定义pid文件路径
pid=
if [ -f "$pid_file" ] ; then # 给定的pid文件是否存在
local line p
[ ! -r "$pid_file" ] && return 4 # "user had insufficient privilege"
while : ; do # 将pid文件中的pid值(可能有多行)赋值给pid变量
read line
[ -z "$line" ] && break
for p in $line ; do
[ -z "${p//[0-9]/}" ] && [ -d "/proc/$p" ] && pid="$pid $p"
done
done < "$pid_file"
if [ -n "$pid" ]; then # pid存在,则返回0。否则表示pid文件存在,但/proc下没有对应命令
return 0 # 即进程已死,但pid文件却存在,返回状态码1。
fi
return 1 # "Program is dead and /var/run pid file exists"
fi
return 3 # "Program is not running" # pid文件不存在时,表示进程未运行,返回状态码3
}
# Output PIDs of matching processes, found using pidof
__pids_pidof() { # 下面的pidof命令的意义见稍后解释
pidof -c -m -o $$ -o $PPID -o %PPID -x "$1" || \ # 忽略当前shell的PID,父shell的pid和
# 调用pidof程序的shell的pid
pidof -c -m -o $$ -o $PPID -o %PPID -x "${1##*/}" # 总之就是找出合理的pid
}
从__pidsvar_run函数的定义语句中可以了解到,只有当pid文件存在,且/proc下有pid对应的目录时,才表示进程在运行(当然,线程没有pid文件)。__pids_var_run函数调用方法:
__pids_var_run program [pidfile]
如果不给定pidfile,则默认为/var/run/$base.pid文件。函数的执行结果为4种状态码:
0:program正在运行。
1:program进程已死。pid文件存在,但/proc目录下没有对应的文件。
3:pid文件不存在。
4:pid文件的权限错误,不可读。
除了返回状态码,__pids_var_run函数还会保存变量pid的结果,以供其他程序引用。
__pids_pidof中使用了pidof命令,其中使用了几个”-o”选项,它用于忽略指定的pid。但看上去$$ $PPID %PPID不是很好理解。-o $$是忽略的是shell进程,大多数时候它会继承父shell的pid,但在脚本中时它代表的是脚本所在shell的pid。-o $PPID忽略的是父shell。-o %PPID忽略的是调用pidof命令的shell。不是很好理解,可以参考下面的测试语句。
测试脚本:
#!/bin/bash
echo 'pidof bash: '`pidof bash`
echo 'script shell pid: '`echo $$`
echo 'script parent shell pid: '`echo $PPID`
echo 'pidof -o $$ bash: '`pidof -o $$ bash`
echo 'pidof -o $PPID bash: '`pidof -o $PPID bash`
echo 'pidof -o %PPID bash: '`pidof -o %PPID bash`
echo 'pidof -o $$ -o $PPID -o %PPID bash: '`pidof -o $$ -o $PPID -o %PPID bash`
测试语句:
[root@xuexi ~]# pidof bash
3306 2436 2302
[root@xuexi ~]# (echo 'parent shell: '$$;echo "current bash pid: `pidof bash`";./test.sh)|cat -n
1 parent shell: 2302
2 current bash pid: 3745 3306 2436 2302
3 pidof bash: 3748 3745 3306 2436 2302
4 script shell pid: 3748
5 script parent shell pid: 3745
6 pidof -o $$ bash: 3745 3306 2436 2302
7 pidof -o $PPID bash: 3748 3306 2436 2302
8 pidof -o %PPID bash: 3745 3306 2436 2302
9 pidof -o $$ -o $PPID -o %PPID bash: 3306 2436 2302
第一个pidof命令:说明当前已有3个bash,pid为:3306、2436和2302。
第二个命令:
行1说明括号的父shell为2302。
行5说明脚本的父shell为3745。即括号的父shell为当前bash环境,脚本的父shell为括号所在shell。
行2减第一个命令的结果说明括号所在子shell的pid为3745。
行3减行2说明shell脚本所在子shell的pid为3748。
-o $$忽略的是当前shell,即脚本所在shell的pid,因为在shell脚本中时,$$不继承父shell的pid。
-o $PPID忽略的是pidof所在父shell,即括号所在shell。
-o %PPID忽略的是调用调用pidof程序所在的shell,即脚本所在shell。
|