我启动了一个无法运行的应用程序,但我无法删除它,因为它仍在运行。我可以打印 PID,但无法终止使用它的进程。
~ $ ps ax | grep snappr | awk '{print $1}'
70824
~ $ kill $(ps ax | grep snappr | awk '{print $1}')
-bash: kill: (70832) - No such process
答案1
您是否注意到,两次尝试中您得到了两个不同的 PID?
考虑一下:如果您输入类似 的命令vi raven.txt
,ps ax
则将显示一行显示 的命令vi raven.txt
。同样,如果您输入类似 的命令grep snappr
,ps ax
则将显示一行显示 的命令。并且,如果您通过grep snappr
管道传输该命令的输出,则将找到该行ps
grep snappr
grep
那就是自我描述。因此,如果你输入
$ ps ax | grep snappr | awk '{print $1}'
重复执行此操作,每次它都会打印一个不同的数字(因为它打印的是 PID ,并且每次运行命令时grep
都会得到一个新的、唯一的进程)。grep
最后,请考虑:kill
只有在知道命令的参数后才能执行该命令。要知道命令的参数,管道$(ps ax | grep snappr | awk '{print $1}')
必须已完成。这意味着 必须grep
已终止1。因此,kill
被赋予了进程的 PID grep
,但只有在grep
进程终止后才会被赋予 PID —— 因此,它自然会报告“没有这样的进程”。
也许我应该提到没有snappr
进程正在运行。如果有,您的第一个命令将输出两个数字:的 PIDsnappr
和 的 PID grep snappr
。现在,如果snappr
正在运行,您的命令可能会开始半正确运行,我的意思是它会执行您想要的操作,但也会给出错误消息。如果 正在snappr
以 PID 42097 运行,并且grep snappr
以 PID 70848 运行,则kill
命令将是kill 42097 70858
,这将终止snappr
并收到错误消息,因为尝试终止grep
不再存在的进程。
您可能想要改进这一点。我最喜欢的方法是将 改为grep
,grep "[s]nappr"
这样可以匹配snappr
但不会匹配自身。另一种方法是使用pgrep
而不是ps | grep
。
1或者,awk
如果grep
仅关闭其 stdout,则可完成。这对于 *nix 程序来说是非常不寻常的行为。
答案2
简短答案
不要跳过 Bash 圈来杀死snappr
它ps
,grep
然后通过管道awk
再通过管道。相反,尝试像这样杀死它pkill
;没有混乱或麻烦,它基于开箱即用的流程名称进行定位:
sudo pkill snappr
较长的答案
不太清楚如何鲷鱼在系统进程级别运行,但问题可能是您只获取子进程 ID 而不是父进程 ID。
事实上,我相信你用来获取进程 ID 的方法 ( ps ax | grep snappr | awk '{print $1}'
) 将返回与之连接的整个进程 ID 列表,snappr
无论它是父进程还是子进程。因此,使用该方法,你可能杀死一个仅仅是子进程 ID 的进程 ID,但父进程 ID 仍然处于活动状态,并且能够“生成”另一个子进程进行补偿。
因此,也许您可以做这样的事情来获取您输入的任何进程 ID 的最终父 ID 并对其采取行动;关于其工作原理的简单概念证明:
ps -p [process ID] -o ppid=
在 Bash 中运行该裸命令将为您提供输入的子进程 ID 的父进程 ID [process ID]
。因此,如果子 ID4567
的父进程 ID 为,123
则命令将是:
ps -p 4567 -o ppid=
那将会返回123
。
话虽如此,但这可能是一种处理离群进程的危险方式,因为如果您的脚本获取了 的实际父进程 ID snapper
,那么该进程 ID 的父进程实际上可能是您自己的 Bash shell。因此,您可能会无意中杀死您的 Bash shell,而不是将snapper
您从系统中剔除,同时让snapper
进程继续运行。
但话虽如此,为什么不让你的生活更轻松一点,直接跑步pkill
像这样:
sudo pkill snappr
这将终止所有连接的进程,snappr
无需任何复杂的命令行操作。