使用pgrep遇到的问题

之前使用了这个启动脚本来管理自己写的一些脚本. 这个脚本使用pgrep来避免同一个程序重复启动.

这几天新添加了一个脚本, 部署之后发现它会多次启动, 但是其它程序都是正常的. 这个新添加的程序没有什么特别的, 多次尝试, 发现是pgrep的问题, 并且和程序名称有关, 具体来看一下.

实验

写两个非常非常简单的脚本来模拟一下

code.sh
1
2
3
#/bin/bash

sleep 1000
this_is_another_test_code.sh
1
2
3
#/bin/bash

sleep 1000

分别运行两个脚本, 在另外一个终端使用pgrep 程序名称来测试, 发现无法获取到后者的pid, 可是程序明明就在运行. 额, 这是什么情况…..

查看说明

我们先man pgrep看一下有没有一些需要注意的地方:

NOTES

The process name used for matching is limited to the 15 characters present in the output of /proc/pid/stat. Use the -f option to match against the complete command line, /proc/pid/cmdline.

The running pgrep or pkill process will never report itself as a match.

给我感觉BUGS, NOTES等段的内容是相当重要, 已经不只一次碰到这样的情况了….

根据说明我们可以知道pgrep是根据proc目录下的相关文件来工作. 我们使用man 5 proc来看看proc的相关说明:

/proc/[pid]/cmdline

This holds the complete command line for the process, unless the process is a zombie. In the latter case, there is nothing in this file: that is, a read on this file will return 0 characters. The command-line arguments appear in this file as a set of null-separated strings, with a further null byte (‘\0’) after the last string.

上面是cmdline的, 我们顺便看下stat的:

/proc/[pid]/stat

Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.

The fields, in order, with their proper scanf(3) format specifiers, are:

pid %d The process ID.

comm %s The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.

到这里我们就可以比较了解问题的原因了, 下面我们来证实一下.

再实验

运行this_is_another_test_code.sh, 我们看一下proc下对应的文件(假设pid为3493)

test
1
2
3
4
5
6
7
$ cat /proc/3493/stat

3493 (this_another_te) S

$ cat /proc/3493/cmdline

/bin/bash./this_another_test_code.sh

因为stat文件对应的cmd段只显示了15个字符, 所以pgrep会失败

结尾

我想出来的解决办法就是: 把程序名字取短一点. 虽然pgrep可以使用-f选项来使用cmdline来进行匹配, 但是因为还包含路径, 就增加了不确定性, 因此最好最简单的方案还是调整程序名字的长度.

Comments