我正在尝试为一个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,但我真的希望从子subshell中运行java进程的pid。
有没有什么方法我可以构造命令,这样我就可以得到subshell命令pid?
谢谢!
发布于 2016-01-16 05:56:45
而不是
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。通过正确配置sudo (请参阅sudo(1)),可以避免fork-ing。但对我来说,设置用户并运行另一个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"发布于 2016-01-16 05:38:15
使用另一个脚本有什么问题:
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发布于 2016-01-16 07:03:43
如果没有shell支持,您就不能做到这一点,而且bash也没有提供正确的原语。更改感兴趣的进程以输出或存储其自己的PID是正确的方法。
如果你不能修改应用程序代码,你可以使用一个简单的包装器,比如:
#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将不是调用的外壳。
https://stackoverflow.com/questions/34819671
复制相似问题