我有以下perl脚本:
#!/usr/bin/perl
use strict;
use warnings;
use Proc::Daemon;
Proc::Daemon::Init;
my $continue = 1;
$SIG{TERM} = sub { $continue = 0 };
while ($continue) {
# stuff
}
我的init脚本中有以下内容:
DAEMON='/path/to/perl/script.pl'
start() {
PID=`$DAEMON > /dev/null 2>&1 & echo $!`
echo $PID > /var/run/mem-monitor.pid
}
问题是,这会返回错误的PID!这将返回运行守护程序时启动的父进程的PID,但该进程会立即终止。我需要得到子进程的PID!
答案 0 :(得分:2)
Proc :: Daemon执行以下操作:
...
9.第一个子节点将第二个子节点(守护进程)的PID传输给父节点。此外,如果定义了'pid_file',则可以将守护进程的PID写入文件。然后第一个孩子退出。
然后在new ( %ARGS )
pid_file
定义文件的路径(由父用户拥有),其中将存储守护进程的PID。默认为undef(=不写文件)。
另请参阅Init()
方法说明。这一切都意味着您可能希望先使用new
。
重点是守护进程的是孙子进程。但是,childr会传递pid,并且父级可以使用它。如果在构造函数(守护程序)中设置了pid_file => $file_name
,则会将pid写入该文件。
评论要求shell脚本不依赖于另一个脚本编写的文件。
我可以看到两种方法。
从父级打印由$daemon->Init()
返回的pid,然后在shell中将其拾取。这被问题中的重定向所击败,但我不知道为什么需要它们。父级和子级在所有设置完成后退出,而守护程序与所有内容分离。
Shell脚本可以使用所需的日志文件名作为参数启动Perl脚本,让它通过上述过程将守护进程pid写入该文件。该文件仍由Perl输出,但重要的是由shell脚本决定的。
我想在下面的评论中加入一条声明。我认为这些优于另外两个想到的事情:从shell保存的配置样式文件中选择文件名更复杂,而解析进程表可能不太可靠。
答案 1 :(得分:1)
我以前见过这个,不得不求助于使用STDERR将子PID发送回调用shell脚本。我一直认为这是由于提到退出代码的不可靠性 - 但文档中的细节并不清楚。请尝试这样的事情:
#!/usr/bin/perl
use strict;
use warnings;
use Proc::Daemon;
if( my $pid = Proc::Daemon::Init() ) {
print STDERR $pid;
exit;
}
my $continue = 1;
$SIG{TERM} = sub { $continue = 0 };
while ($continue) {
sleep(20);
exit;
}
使用这样的调用脚本:
#!/bin/bash
DAEMON='./script.pl'
start() {
PID=$($DAEMON 2>&1 >/dev/null)
echo $PID > ./mem-monitor.pid
}
start;
运行bash脚本时,它将捕获STDERR输出(包含正确的PID),并将其存储在文件中。 Perl脚本生成的任何STDOUT都将被发送到/ dev / null - 尽管这不太可能,因为第一级Perl脚本(在这种情况下)很早就退出了。
答案 2 :(得分:0)
感谢zdim和Hakon的建议。它们肯定是可行的,让我走上了正确的轨道,但最终我走了另一条路。我使用$!
和ps
来获取PID,而不是依赖awk
,如下所示:
DAEMON='/path/to/perl/script.pl'
start() {
$DAEMON > /dev/null 2>&1
PID=`ps aux | grep -v 'grep' | grep "$DAEMON" | awk '{print $2}'`
echo $PID > /var/run/mem-monitor.pid
}
这可以满足我的强迫症!请注意grep "$DAEMON"
中“$ DAEMON”周围的双引号。