2017-02-17 120 views
0

我有以下perl腳本:如何在init腳本中獲得perl守護進程的PID?

#!/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!

+1

查看['Proc :: Daemon']的文檔(https://metacpan.org/pod/Proc::Daemon)。有一個選項叫做'pid_file'。 PID將被寫入該文件。 –

+0

是的,我知道我可以在Perl中使用這個選項。但是,我想在init腳本中保留這樣的功能(創建,刪除PID文件),而不是在perl中完成1/2,在init腳本中完成1/2。 – Bintz

+0

您可以嘗試在命令行上將shell腳本的文件名傳遞給Perl腳本,例如'$ DAEMON $ pid_file>/dev/null 2>&1 ....'然後Perl腳本可以使用這個文件名'$ pid_file'來創建pid文件 –

回答

0

謝謝zdim和Hakon的建議。他們肯定是可行的,並讓我走上正軌,但最終我走了另一條路。而不是依靠$!,我用psawk得到PID,如下所示:

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 
} 

這工作,並滿足我的強迫症!請注意0​​中「$ DAEMON」的雙引號。

2

Proc::Daemon

PROC ::守護程序將執行以下操作:
...
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腳本可以用所需的日誌文件名作爲參數啓動Perl腳本,讓它通過上述過程將守護程序pid寫入該文件。該文件仍然由Perl輸出,但重要的是由shell腳本決定的。

我想在下面的評論中添加一條語句。我認爲這些優於其他兩件事情:從shell保存的配置風格文件中選擇文件名比較複雜,而解析進程表可能不可靠。

+0

謝謝你的解釋。有沒有辦法從shell中訪問大孩子的PID?正如我在對原始問題的評論中指出的那樣,我寧願避免在Perl腳本中創建PID文件。這對我來說不算什麼,因爲init腳本將不得不依賴Perl腳本創建的文件。 – Bintz

+0

@Bintz我認爲這是合理的。我添加了兩個我可以看到的帖子。我能想到的另外兩個看起來不太好 - (1)Perl腳本從文件夾中保存的某種配置文件中獲取文件名。這會比將腳本文件傳遞給腳本更加複雜並且沒有更好,如答案(2)Shell通過跟蹤和分析進程表來找到pid。那會非常麻煩和不可靠。 //我還沒有看到其他方法。 – zdim

1

我以前見過這種情況,不得不求助於使用STDERR將childs 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腳本(在這種情況下)很早就退出了。