我正在检索我想要杀死的两个 PID 的列表。我的管道看起来像
ps -ef | grep foo | grep -v grep | awk {'print $2'} | xargs kill -9
在本地执行此操作时,两个进程都会被终止。但是当与 ssh 一起使用时
ssh foo@<IP Address> "ps -ef | grep foo | grep -v grep | awk {'print $2'} | xargs kill -9"
两个 PID 中只有一个被删除。它输出kill: <PID>: No such process
.它可能试图在本地杀死第二个进程吗?
答案1
本地 shell 命令行上的位于$2
双引号内,因此由本地 shell 扩展(可能为空字符串)。
因此,在远程主机上运行的命令类似于:
ps -ef | grep foo | grep -v grep | awk {'print '} | xargs kill -9
该awk
命令是一个无操作(打印所有行)并且xargs
最终将运行:
kill -9 <all-the-words-present-in-the-output-of-ps|grep...>
其中包括 pid 和 ppid、用户名...
此外,如果 kill 命令的 pid 在该列表中,它将杀死自身,因此无法杀死列表中的剩余进程。
在这里,您想要:
ssh foo@<IP Address> 'pkill -KILL -f foo'
(杀死命令行(至少前几千字节)包含 的所有进程foo
)。
或者如果远程系统没有pkill
命令:
ssh foo@<IP Address> '
ps -Ao pid= -o args= |
awk "/[f]oo/ {print \$1}" |
xargs kill -s KILL'
我们在本地端使用单引号(因此那里没有变量扩展),并在远程 shell 命令行中对 awk 代码使用双引号,因此我们需要对 in 进行转义,$
以便$1
它不会被远程 shell 扩展。
awk
是 的超集grep
,通常不需要将它们通过管道连接在一起。最好是告诉只输出您想要匹配的内容,这里假设您要按照您的使用建议在 ps 显示的参数列表中ps
搜索。foo
-f
如果你想终止远程用户的所有进程(这里是用户 foo 和 sshing as foo),你可以这样做:
ssh foo@<IP Address> 'kill -s KILL -- -1'
这将杀死用户有权杀死的所有进程。对于普通用户来说,就是真实或保存的设置用户id与查杀进程的真实或有效用户id相同的所有进程。
或者:
ssh foo@<IP Address> 'pkill -KILL -U "$(id -u)"'
(或者pkill -U foo
)。杀死所有真实用户ID与远程用户的有效用户ID相同的进程。
或者你可以这样做:
ssh foo@<IP Address> '
trap "" HUP
ps -Ao sid= -o pid= -U "$(id -u)" |
awk "\$1 != $(ps -eo sid= -p "\$\$") {print \$2}" |
xargs kill -s KILL'
(检查sid
以免kill
杀死自身、shellawk
或xargs
,并忽略 SIGHUP,以防杀死用户sshd
进程导致发送该信号)
我们假设远程用户的登录 shell 与 Bourne 类似。例如,如果远程用户的登录 shell 属于具有不同语法的 csh 或 rc 系列,则必须调整这些命令。
更好的做法是通过名称而不是编号来引用信号,因为这样会更清晰,并且信号编号可能会因系统而异(SIGKILL 的 9 是相当通用的)。
答案2
简而言之,试试这个
ssh user_name@ip_address "pkill -9 foo"
或者如果你想要长的
ssh user_name@ip_address "ps aux | grep '[f]oo' | awk '{print \"kill -9 \"\$2}' | bash -v"