使用 ssh 将两个 PID 的列表传递给 xargs 仅杀死第一个

使用 ssh 将两个 PID 的列表传递给 xargs 仅杀死第一个

我正在检索我想要杀死的两个 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杀死自身、shellawkxargs,并忽略 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"

相关内容