有时我需要终止一个进程(原因并不重要)。我知道我可以使用以下命令找到该过程:lsof -i :8080
,成为我的候选人最后一道工序在输出表中。
例如,如果我运行该命令,将出现如下输出:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 15112 dani 70u IPv4 3178183 0t0 TCP localhost:39998->localhost:http-alt (CLOSE_WAIT)
java 15112 dani 137u IPv4 3181607 0t0 TCP localhost:39999->localhost:http-alt (CLOSE_WAIT)
java 15112 dani 138u IPv4 3181608 0t0 TCP localhost:40000->localhost:http-alt (CLOSE_WAIT)
java 15112 dani 139u IPv4 3181609 0t0 TCP localhost:40001->localhost:http-alt (CLOSE_WAIT)
java 15112 dani 140u IPv4 3181610 0t0 TCP localhost:40002->localhost:http-alt (CLOSE_WAIT)
java 19509 dani 50u IPv6 4617361 0t0 TCP *:http-alt (LISTEN)
java 19509 dani 52u IPv6 6642445 0t0 TCP localhost:http-alt->localhost:42996 (CLOSE_WAIT)
所以,我的目标是PID 19509。使用管道,我如何挑选最后一行的 PID?
我想达到这样的命令lsof -i :8080 | something here to get the PID | kill -9
我正在运行 Linux Mint KDE x64
答案1
从字面上回答你的问题,这是列出最后显示的 PID 的一种方法lsof
:
lsof … | awk 'END {print $2}'
awk是一种文本处理语言,它读取输入并逐行处理它。代码中,END {…}
处理完整个输入后执行大括号内的代码,并对最后一行进行有效操作。$2
是该行中第二个空格分隔的字段。
这里有一些杀死它的方法(每行都独立工作):
kill $(lsof … | awk 'END {print $2}')
lsof … | awk 'END {print $2}' | xargs kill
lsof … | awk 'END {system("kill " $2)}'
然而,我对你的说法提出异议,即杀死正确的进程总是最后一个进程。lsof
通过增加PID来显示进程,这是没有意义的。即使在进程 ID 按顺序分配的系统上(并非所有 Unix 变体,甚至并非所有 Linux 安装),一旦达到最大值(通常为 32767),它们就会换行。因此通过比较 PID 来决定进程是没有意义的。
您需要一些其他信息来决定要终止哪个进程。根据您想要的信息类型以及您的输出是否可能包含“奇怪”字符(例如文件名或程序名中的空格),您可以使用 awk 等工具来处理 的输出lsof
,或者您可以使用该-F
选项lsof
产生的输出在简单情况下解析起来有点困难,但(几乎)不容易产生歧义并且更容易稳健地解析。例如,如果您想终止正在侦听端口 8080 的任何进程,可以按以下方法操作:
lsof -n -i :8080 -F | awk '
sub(/^p/,"") {pid = $0}
$0 == "n*:http-alt" {print pid}
' | xargs kill
对该函数的调用将行的开头sub
替换为空字符串。p
如果执行此替换,则{pid = $0}
执行该代码块;这样pid
变量就包含了显示的最后一个 PID 值lsof
。pid
如果该行恰好是,则第二个 awk 行将打印变量的值"n*:http-alt"
,这是 lsof 报告在所有接口上侦听端口 8080 的套接字的方法。
这个特定的标准实际上不需要任何解析(我只在上面作为示例展示)。您可以使lsof
显示仅在指定端口上侦听的进程:
lsof -n -a -iTCP:8080 -sTCP:LISTEN -Fp | sed 's/^p//' | xargs kill
或者,为此,您可以使用netstat
反而。
netstat -lnpt | awk '$4 ~ /:8080$/ {sub(/\/.*/, "", $7); print $7}'
awk 代码说明:如果第 4 列以 结尾:8080
,则替换第 7 列中第一列之后的所有内容/
(删除进程名称部分并仅保留 PID 部分),然后打印它。