我正在尝试为java程序编写init服务脚本。我在init脚本中有以下内容。
$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。
无论如何我可以构造命令,所以我得到了subshell命令pid吗?
谢谢!
答案 0 :(得分:2)
而不是
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
通常会生成子进程并在其中调用exec
。通过fork
的正确配置可以避免sudo
- (请参阅sudo(1)
)。但是我似乎更容易设置用户并运行另一个shell。
这种方法似乎比通过ps | grep | blabla
获取进程的pid更好,因为它避免了竞争条件:一旦shell运行了后台进程,获取pid的唯一正确方法是打印$!
变量。否则,如果java
很快终止,我们就会得到一个错误的程序的pid,甚至根本就没有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"
答案 1 :(得分:1)
使用其他脚本的原因是什么:
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
答案 2 :(得分:1)
如果没有shell支持,你就无法做到这一点,而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。