.pid 文件是什么
1. 概述
有时需要保存 Linux 进程的进程标识号(PID)。本教程中,我们将介绍一种使用 .pid 文件存储 PID 的常见方法,以及如何使用它的示例。
2.何为 .pid 文件?
有时,应用程序会将 PID 写入文件以便于访问。它只是一个仅包含进程 PID 的文本文件。关于创建或使用没有具体的规则。这只是一个有益的惯例。
让我们从创建 .pid 文件的一个简短示例开始。
3. 创建 .pid 文件
现在让我们讨论一下 .pid 文件的创建。
3.1. 初始文件创建
使用脚本创建 .pid 文件的一种方法是将 $$
的输出通过管道写入到文件:
% echo $$ > myShell.pid
% cat myShell.pid
40276
$$
是一个 Linux 变量,它返回调用它的进程的 PID。本例中,它是 shell 的 PID。
现在,让我们从一个小脚本开始:
#!/bin/bash
# create file
pid_file="process.pid"
echo $$ > $pid_file
count=0
while [ $count -le 10 ]
do
echo Going $count..
sleep 1
count=$(($count+1))
done
当我们运行该脚本时:
% ./process.sh
我们可以看到两样东西。首先,我们可以看到该进程的输出:
% ./process.sh
Going 0..
Going 1..
Going 2..
Going 3..
Going 4..
Going 5..
Going 6..
Going 7..
Going 8..
Going 9..
Going 10..
如果在另外一个终端窗口中运行 ls
,我们将考到 process.pid
文件:
% ls
process.pid process.sh
它包含运行该脚本的进程的 PID。我们可以在该文件上使用 cat
来对此进行验证:
% cat process.pid
34876
3.2. .pid 文件位置
虽然我们可以将 .pid
文件放在任何地方,但通常我们会让我们的进程将该文件放在 /var/run
中。为了避免与其他进程冲突,我们可以更进一步,创建一个新目录 /var/run/myScript
:
% echo $$ > /var/run/myScript/myShell.pid
在有些系统中,该目录可能由 root
所有,这种情况下我们无法将 .pid
文件写入到那个位置。因此,第二个选项是 home 目录:
% $$ > ~/myScript/myShell.pid
4. 通过 .pid
文件终止进程
现在我们有了一个进程的 .pid
文件,让我们考虑一下我们可以用它做什么。
假设我们想在进程运行时终止它。如果有一个 .pid
文件,我们可以从该文件中获取 pid,然后将其与 xargs
和 kill
一起使用。这确保了我们只需要知道 .pid
文件的名称和位置,而不需要知道实际的 PID 本身:
% cat process.pid | xargs kill
此处的主要好处是,我们终止了我们想要终止的进程。我们可以这样做:
ps -ef | grep process
但是,如果有多个应用实例在运行中,这样做可能会产生多个结果。它还将显示实际运行 grep
的进程,例如:
% ps -ef | grep process
501 40311 40276 0 7:00AM ttys001 0:00.00 grep process
在这种情况下,我们必须在终止任何东西之前考虑意外的匹配。
5. 确保应用的单一实例
我们还可以使用 .pid
文件来确保应用在我们启动它之前尚未运行。为此,我们的脚本需要进行两个修改。首先,我们需要在运行结尾处删除 .pid
文件:
# clean up file after we're done
rm $pid_file
其次,我们需要在开头添加一个检查,以检查是否存在 .pid
文件:
if [ ! -f $pid_file ]; then
echo "Creating .pid file $pid_file"
echo $$ > $pid_file
else
echo "Found .pid file named $pid_file. Instance of application already exists. Exiting."
exit
fi
如果文件存在,我们将假设应用正在运行中,并且在不运行脚本其余部分的情况下退出。
现在,这个脚本像这样:
#!/bin/bash
# create file
pid_file="process.pid"
if [ -f $pid_file ]; then
echo "Found existing .pid file named $pid_file. Exiting."
exit
else
echo "Creating .pid file $pid_file"
echo $$ > $pid_file
fi
count=0
while [ $count -le 10 ]
do
echo Going $count..
sleep 1
count=$(($count+1))
done
# clean up file after we're done
rm $pid_file
要查看此操作,让我们打开两个终端窗口并在其中运行我们的脚本:
% ./process.sh
第一个窗口将如我们预期的那样运行:
% ./process.sh
Creating .pid file process.pid
Going 0..
Going 1..
Going 2..
第二个窗口将检测到 .pid
文件,并且退出而不运行:
% ./process.sh
Found existing .pid file named process.pid. Exiting.
6. 处理过期的 .pid 文件
我们可能会在这个实现中遇到的一个问题是过期的 .pid
文件。假设应用在没有到达清理我们的 .pid
文件那一行时死亡。如果我们重新启动应用,文件仍然存在,脚本将退出而不运行。
我们可以延长我们的启动检查来处理这种情况。我们可以确保,如果 .pid
文件存在,而其中的 PID 也是一个有效的进程。让我们尝试在 .pid
文件的内容上使用 pgrep
:
pgrep -F process.pid
如果进程匹配 PID,它将返回退出码 0,而如果没有匹配该 PID 的进程则返回 1。
这样,我们的脚本将在开始处添加两个检查:
#!/bin/bash
# create file
pid_file="process.pid"
if [ -f $pid_file ]; then
echo "Found existing .pid file named $pid_file. Checking."
# check the pid to see if the process exists
pgrep -F $pid_file
pid_is_stale=$?
old_pid=$( cat $pid_file )
echo "pgrep check on existing .pid file returned exit status: $pid_is_stale"
if [ $pid_is_stale -eq 1 ]; then
echo "PID $old_pid is stale. Removing file and continuing."
rm $pid_file
else
echo "PID $old_pid is still running or pgrep check errored. Exiting."
exit
fi
else
echo "Creating .pid file $pid_file"
echo $$ > $pid_file
fi
count=0
while [ $count -le 10 ]
do
echo Going $count..
sleep 1
count=$(($count+1))
done
# clean up file after we're done
rm $pid_file
要查看“过期文件”逻辑的工作情况,请在命令行启动应用,并立即使用 CTRL+c
将其终止。这将生成并留下一个过时的 .pid
文件。再次启动脚本,我们将看到:
./process.sh
Found existing .pid file named process.pid. Checking.
pgrep check on existing .pid file returned exit status: 1
PID 35975 is stale. Removing file and continuing.
Going 0..
Going 1..
通过在一个窗口中启动应用,然后在另一个窗口立即启动它,我们可以看到“仍在运行”的逻辑。我们将在第二个窗口中看到:
% ./process.sh
Found existing .pid file named process.pid. Checking.
35926
pgrep check on existing .pid file returned exit status: 0
PID 35926 is still running or pgrep check errored. Exiting.
所以现在,我们有一个脚本,它使用 .pid
文件来确保我们一次只运行一个应用实例。
7. 结论
本文中,我们使用 .pid
文件来跟踪进程的 PID。