我想启动进程(例如myCommand)并获取其pid(以允许稍后将其杀死)。

我尝试了ps并按名称进行过滤,但是我无法按名称区分进程。

myCommand
ps ux | awk '/<myCommand>/ {print }' 


因为进程名称不是唯一的。 />
我可以通过以下方式运行进程:

myCommand &


我发现我可以通过以下方式获取此PID:

echo $!


有没有更简单的解决方案?

我很乐意执行myCommand并通过一行命令获得其PID。

#1 楼

有什么比echo $!更简单的?作为一行:

myCommand & echo $!


评论


谢谢您将这些命令与“&”合并对我有很大帮助。

–rafalmag
2010-11-27 12:09

在bash脚本中,在启动程序的循环中,$!是不准确的。有时它返回脚本本身的pid,有时从脚本中返回grep或awk运行的任何解决方案,以专门获取在这种情况下刚启动的进程的pid?像pid = myprogram这样的东西真棒

–user217730
2014年4月26日在5:59

注意,这要求您使用&作为上一行来启动命令,否则echo基本上返回空白。

–rogerdpack
15年2月4日在18:56

分配给像command&echo $这样的变量!在这一步冻结执行:(

– Shashank Vivek
16年7月15日在9:41

如果您没有明确后台该过程,则此方法不起作用!例如,您的进程在完成需要继续执行的操作之前可能会使其本身成为后台。

–迈克尔
20年4月16日在0:10

#2 楼

您甚至可以在运行命令之前使用sh -cexec来获取命令的PID。

要启动myCommand,以便在开始运行之前打印其PID,可以使用:

sh -c 'echo $$; exec myCommand'


工作原理:

这将启动一个新的shell,打印该shell的PID,然后使用内置的exec用您的命令替换该shell,确保它具有相同的PID。当您的shell运行带有内置exec的命令时,您的shell实际上正在成为该命令,而不是派生自己的新副本的更常见的行为,该副本具有自己独立的PID,然后成为命令。

我发现,这比涉及异步执行(使用&),作业控制或使用ps进行搜索的方法要简单得多。这些方法很好,但是除非您有特定的理由使用它们(例如,也许该命令已经在运行,在这种情况下搜索其PID或使用作业控制才有意义),我建议您首先考虑采用这种方法。 (而且我当然不会考虑编写复杂的脚本或其他程序来实现此目的。)

此答案包括此技术的示例。


各部分

即使您使用的shell是Bourne风格的,因此支持具有这些语义的exec内置命令,您通常也不应该避免为此,请使用sh -c(或等效命令)创建一个新的单独的shell进程,因为:


一旦shell变为myCommand,就没有shell等待运行后续命令了。将sh -c 'echo $$; exec myCommand; foo替换为foo后,将无法尝试运行myCommand。除非您编写的脚本是最后一个运行该脚本的脚本,否则不能仅在运行其他命令的shell中使用echo $$; exec myCommand
您不能为此使用子外壳。 (echo $$; exec myCommand)在语法上可能比sh -c 'echo $$; exec myCommand'更好,但是当您在$$ (内运行)时,它将给出父外壳的PID,而不是子外壳本身的PID。但是,子外壳的PID将成为新命令的PID。一些外壳程序提供了自己的非便携式机制来查找子外壳程序的PID,您可以将其用于此目的。尤其是在Bash 4中,(echo $BASHPID; exec myCommand)确实可以工作。

最后,请注意,某些shell在执行命令时会执行优化,就像exec一样(即,它们首先放弃分叉)(已知时)这样,shell之后便无需执行任何操作。一些shell会尝试在它是最后一个要运行的命令时执行此操作,而其他shell只会在该命令之前或之后没有其他命令时执行此操作,而其他shell则根本不会执行。这样做的结果是,如果您忘记编写exec而仅使用sh -c 'echo $$; myCommand',那么在某些具有某些shell的系统上,有时它会为您提供正确的PID。我建议您不要再依赖这种行为,而是在需要时始终添加exec

评论


在运行myCommand之前,需要在bash脚本中设置许多环境变量。这些会继续执行exec命令的环境吗?

–user5359531
18年5月11日在15:41

看起来我的环境确实继承了exec命令。但是,当myCommand启动您需要使用的其他进程时,该方法不起作用。当我发出以这种方式获取pid的kill -INT 时,信号不会到达myCommand启动的子进程,而如果我在当前会话和Ctrl + C中运行myCommand,则信号会正确传播。

–user5359531
18年5月11日在16:43



我试过了,但是myCommand进程的pid似乎是echo $$ +1所输出的pid。难道我做错了什么?

– crobar
18年8月28日在10:13

我的命令如下:sh -c'echo $$; exec / usr / local / bin / mbdyn -f“ input.file” -o“ / path / to / outputdir”>“ command_output.txt” 2>&1&'

– crobar
18年8月28日在10:51

这很棒,但是当我尝试将回显的值转换为变量时,它对我不起作用,因此我以后可以实际使用它来终止该过程,例如PID = $(sh -c'echo $$; exec myCommand')只是挂起,而如果我删除PID = $(...)包装器,它将显示PID并立即继续!

–迈克尔
20 Apr 16'0:22

#3 楼

将命令包装在一个小的脚本中

#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file


#4 楼

我不知道有任何更简单的解决方案,但是没有使用$!够好了?正如其他人所说,如果以后需要,您可以始终将值分配给其他变量。

作为补充,可以使用pgreppidof代替ps的管道。

#5 楼

将pid注册到文件后,使用bash脚本中的exec:

示例:

假设您有一个要与args一起运行的名为“ forever.sh”的脚本p1,p2,p3

forever.sh源代码:

#!/bin/sh

while [ 1 -lt 2 ] ; do
    logger "
#!/bin/sh

echo $$ > /var/run/.pid
exec "$@"
running with parameters \"$@\"" sleep 5 done


创建收割者。sh:

./reaper.sh ./forever.sh p1 p2 p3 p4 &


通过reaper.sh永久运行以下命令:

cat /var/run/forever.sh.pid 
5780


现在,您在/var/run/forever.sh.pid中有了pid。

syslog grep:

Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"


您可以在进程表中看到它:

ps axuwww|grep 'forever.sh p1' |grep -v grep
root      5780  0.0  0.0   4148   624 pts/7    S    16:07   0:00 /bin/sh ./forever.sh p1 p2 p3 p4


评论


哦,还有“ oneliner”:/ bin / sh -c'echo $$> / tmp / my.pid && exec program args'&

–user237419
2010-11-24 14:28

要在参数中正确保留内部空格,应使用exec“ $ @”而不是exec $ *。从技术上讲,您需要保留的不是空格,而是IFS shell参数(默认为空格,制表符和换行符)中字符的出现。

–克里斯·约翰森(Chris Johnsen)
2010-11-25 3:53



点。 :)

–user237419
10 Nov 25'7:54

谢谢,我不知道$$参数。这可能非常有用。

–rafalmag
10-11-27在12:12

#6 楼

在bash shell中,$!的替代方法可能是内置的jobs -p。在某些情况下,!中的$!在(而不是在)变量扩展之前被shell解释,从而导致意外结果。例如,这将不起作用:

((yourcommand) & echo $! >/var/run/pidfile)


而这将是:

((yourcommand) & jobs -p >/var/run/pidfile)


评论


我认为您的意思是((yourcommand)&jobs -p> / var / run / pidfile)。

–Dom
17年11月13日在20:33



#7 楼

您可以使用以下命令:

$ myCommand ; pid=$!




$ myCommand && pid=$!


这两个命令可以使用;&&。在第二种情况下,仅当第一个命令成功时才设置pid。您可以从$pid获取进程ID。

评论


OP希望获取PID,以便稍后可以杀死它。 ;和&&要求在回显$!之前退出原始过程!被执行。

–user9517
2010-11-24 8:58

是的,你是对的。 myCommand终止后,这将为您提供pid。

–卡乐德
2010-11-24 9:02

引用$!在&&或;之后永远不会给您命令分隔符左侧开始的进程的PID。 $!仅为异步启动的进程设置(例如,通常使用&,但某些shell也具有其他方法)。

–克里斯·约翰森(Chris Johnsen)
2010年11月24日,9:47

这很有帮助,为什么除了我之外没有人投票?不错,虽然:)

–寺庙
16-09-28在21:14

#8 楼

这有点不合逻辑,对大多数人来说不太可能。这也是一个巨大的安全风险方法,因此,除非您确定自己会安全并且输入已被清理,然后...明白,否则不要这样做。

编译将小C程序转换成名为start(或您想要的任何名称)的二进制文件,然后以./start your-program-here arg0 arg1 arg2 ...的身份运行程序。长话短说,这将把PID打印到stdout ,然后将程序加载到进程中。它应该仍然具有相同的PID。

评论


如何在bash变量中记录此代码返回的PID号?由于我不清楚的原因,此示例中似乎未记录stdout:RESULT =“ $(./ start_and_get_pid.out echo yo)”;回声“ $ RESULT”

– Tfb9
18年11月8日在1:27



@ Tfb9:老实说,我推荐其他方法之一。我在2年前写了这篇文章,到目前为止,它是目前所介绍的骇客/容易出错的方法之一(或者我认为)。

–tonysdg
18年11月8日在1:30

感谢您的来信。我想我通过睡眠10和PID_IS = $!解决了我的问题。回声$ PID_IS

– Tfb9
18年11月9日,0:33