杀死监听端口3000的进程的Shell脚本?

88

我想定义一个bash别名名为kill3000,以自动化以下任务:

$ lsof -i:3000

COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
ruby    13402 zero    4u  IPv4 2847851      0t0  TCP *:3000 (LISTEN)

$ kill -9 13402

为什么你想要一个别名而不是一个Bash函数? - Basile Starynkevitch
1
我会编写一个函数,首先执行 kill -TERM,然后再执行 kill -KILL,因为在没有给进程正确终止的机会的情况下杀死进程是不合适的。 - Basile Starynkevitch
@SteveChambers这怎么可能是个重复问题,明明是在那个回答之前就写好了?荒谬... - Jonathan
6个回答

123
alias kill3000="fuser -k -n tcp 3000"

4
我选择这个作为答案的原因是因为我后来发现,当我在Web浏览器中访问服务器时,lsof -i:3000会返回多个进程(例如):ruby 587 zero 10u IPv4 2239530 0t0 TCP localhost:3000->localhost:45341 (ESTABLISHED) firefox 26843 zero 63u IPv4 2238948 0t0 TCP localhost:45337->localhost:3000 (ESTABLISHED)我发现,fuser -n tcp 3000最准确地返回原始进程,所以可能是最可靠的使用方法。 - Jonathan
8
我注意到的是fuser无法区分本地连接和远程连接 - 所以如果你有一个进程连接到远程端口3000,它也会被关闭。仅供参考。 - synthesizerpatel
3
注意,fuser 默认会发送 SIGKILL 信号。你可以使用不同的信号来代替,默认信号。例如,你可以这样告诉它使用不同的信号:fuser -k -TERM -n tcp 3000 - Stephane Chazelas
由于某种原因,这对我不起作用。在我发出命令并执行 netstat -tulpn | grep 8001 后,我仍然会得到该进程的 pid。我正在尝试杀死一个监听 tcp 端口的进程 - fuser -k -n tcp 8001。 - user590849
8
无法在OSX上运行: 未知选项:k 未知选项:n - Dmitri Zaitsev
显示剩余2条评论

75

试试这个:

kill -9 $(lsof -i:3000 -t)

-t 标志是您想要的:它显示PID,仅此而已。

更新

如果未找到该进程并且您不想看到错误消息,请使用以下命令:
kill -9 $(lsof -i:3000 -t) 2> /dev/null

假设您正在运行bash。

更新

Basile的建议非常好:我们应该首先尝试正常终止进程,使用kill -TERM,如果失败,则使用kill -KILL(也称为kill -9):

pid=$(lsof -i:3000 -t); kill -TERM $pid || kill -KILL $pid

您可能希望将其作为bash函数使用。


3
我建议先使用 kill -TERM,然后再使用 kill -KILL - Basile Starynkevitch
我也会在脚本中使用 tcp,例如 lsof -i tcp:3000,以便更精确。 - Ciro Santilli OurBigBook.com

12

使用原始的 lsof 命令的另一种选项:

lsof -n -i:3000 | grep LISTEN | awk '{ print $2 }' | uniq | xargs kill -9

如果您想在shell脚本中使用它,可以添加-r标志到xargs,以处理没有进程正在侦听的情况:

... | xargs -r kill -9

synthesizerpatel: 我个人并不太在意那个“参数不足”的提示信息。如果kill命令没有得到输入,它也不会像疯了一样射击你的init进程(如果我错了,请纠正我 ;) - Niklas B.
1
如果你在一个带有‘set -e’或‘#!/usr/bin/bash -e’的shell脚本中写了类似于这样的代码,kill命令失败会导致整个脚本失败。我的座右铭是:如果可以静默成功,就尽量避免出现失败,但无论如何都要返回一个有用的退出码。 - synthesizerpatel
@synthesizerpatel:没错,但如果我只是从命令行中使用它(“自动化例程”),实际上我想知道是否有东西被终止,这是一个简单的方法来实现这一点 :) 在shell脚本内,我可能会添加-r或使用|| true,这样我至少可以看到错误信息。 - Niklas B.
呵呵,我只是因为测试了lsof版本才发现这个问题的。如果您有一个绑定到多个接口的服务,则lsof方法也会产生两个相同的PID。我不是在挑剔你 - 我发誓。以前从未见过lsof -i:NNNN标志。哦,我建议使用“-n”,这样lsof就不会尝试反向查找任何主机。 - synthesizerpatel
我认为还有一个优化点,可以使用 lsof -t -i4TCP:8090 -sTCP:LISTEN 命令进一步调整 IP 地址,例如 lsof -t -i4TCP@localhost:8090 -sTCP:LISTEN。这样可以确保只有一个结果。 - synthesizerpatel
显示剩余3条评论

5

fuser -k 3000/tcp 也应该可以工作。


4

你能行吗?

alias kill3000="lsof -i:3000 | grep LISTEN | awk '{print $2}' | xargs kill -9"

3
fuser -n tcp 3000

将产生以下输出

3000/tcp:     <$pid>

所以你可以这样做:

fuser -n tcp 3000 | awk '{ print $2 }' | xargs -r kill

我相当确定这里使用 awk 是不必要的,而且还会失败。通过操作 fuser 的输出,我最终意识到看起来像第一列的实际上是 stderr。 - Brian Peterson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接