2016-01-15 91 views
0

我正在嘗試爲java程序編寫一個init服務腳本。我在init腳本中有以下內容。獲取子shell命令的pid

$USER = awesomeuser 

$PROGRAM_CMD = "java -server com.test.TestClass" 

$PROGRAM_LOG = "/var/log/awesome_log" 

sudo -u $USER nohup $PROGRAM_CMD >> $PROGRAM_LOG 2>&1 </dev/null & 
server_pid=$! 
echo $server_pid > $pidfile 

發生了什麼是我得到父進程的PID,但我真的想要從子shell內運行的Java進程的PID。

是否有無論如何我可以構造命令,所以我得到的subshel​​l命令pid回來?

謝謝!

+0

'$ USER = awesomeuser' - 這真的是'bash'嗎?看起來像PHP。 –

+3

你需要學習基本的'bash'語法。變量賦值就像'USER = awesomuser' - 變量前面沒有'$',並且在'='周圍沒有空格。 – Barmar

回答

0

有什麼關於使用其他腳本:

findpid.sh

#!/bin/bash 
pid="" 
pidfile="pid.log" 

while [ -z "${pid}" ]; do 
    pid=`ps -U "${1}" | grep "${2}" | xargs | cut -d" " -f 1` 
done 

echo "${pid}" > ${pidfile} 

然後在你的腳本中調用findpid.sh。您可以在調用java時使用時間戳,以確保您使用ps來確定正確的過程。

#!/bin/bash 
USER=awesomeuser 
TIME=`date +"%s"` 
PROGRAM_CMD="java -server com.test.TestClass java -Dtime=${TIME}" 
PROGRAM_LOG="awesome_log" 

bash findpid.sh "${USER}" "${PROGRAM_CMD}" & 
sudo -u $USER nohup $PROGRAM_CMD >> $PROGRAM_LOG 2>&1 </dev/null & 
wait 
+0

工程很好,但可能存在競爭條件:在調用此序列時,進程可能已經死亡。 –

+0

'ps | grep name'有很大的機會產生錯誤的進程。 – msw

+0

@msw你是對的。如果java被啓動兩次,那麼不正確的pid會被檢索到。通過在java調用中包含時間戳,ps將有更好的機會確定正確的過程。 – jyvet

0

而不是

sudo -u $USER nohup $PROGRAM_CMD >> $PROGRAM_LOG 2>&1 </dev/null & 

試試這個:

sudo -u $USER bash -c "nohup $PROGRAM_CMD >> $PROGRAM_LOG 2>&1 & </dev/null; echo "'$!' 

sudo通常派生子進程和調用execfork -ing可通過sudo的適當配置避免(請參閱sudo(1))。但是,我設置用戶並運行其他shell似乎更容易。

這種方法對我來說比通過ps | grep | blabla獲得進程的pid更好,因爲它避免了競爭條件:一旦shell運行了後臺進程,獲得pid的唯一正確方法是打印$!變量。否則,我們可以得到一個錯誤的程序的PID,或者如果java很快終止,甚至不會得到PID。

順便說一句,以分配合適的值給你的變量,你的腳本的起始線應

USER=awesomeuser 
PROGRAM_CMD="java -server com.test.TestClass" 
PROGRAM_LOG="/var/log/awesome_log" 

,而不是

$USER = awesomeuser 
$PROGRAM_CMD = "java -server com.test.TestClass" 
$PROGRAM_LOG = "/var/log/awesome_log" 
0

無殼支持你不能做到這一點, bash不提供原型來做正確的事情。改變有趣的過程來輸出或存儲自己的PID是正確的方法。

如果你不能改變應用程序代碼,您可以使用cheezy包裝,如:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 

/* 
* pidder cmd args - launch cmd with args and print its pid 
*/ 

int 
main(int argc, char *argv[]) 
{ 
    if (argc < 2) { 
     fprintf(stderr, "usage: pidder command [args]\n"); 
     exit(2); 
    } 

    switch(fork()) { 
     case -1: 
      perror("fork"); 
      exit(2); 
     case 0: 
      printf("%d\n", getpid()); 
      /* launch cmd with path search if relative path */ 
      execvp(argv[1], argv+1); 
      perror("exec"); 
      exit(1); 
     default: 
      exit(0); 
    } 

} 

如果你使用這個,要知道,$ ./pidder some_command也會有細微的差別,從$ some_command,一個簡單的例子是,在第一種情況下,PPID不會是調用shell。

+0

您是否檢查過我的答案?爲什麼你認爲shell不能用來做對吧? –