2016-01-15 106 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不能用来做对吧? –