Passar uma lista de dois PIDs para xargs somente mata o primeiro usando ssh

4

Estou recuperando uma lista de dois PIDs que desejo matar. Meu pipeline parece algo como

ps -ef | grep foo | grep -v grep | awk {'print $2'} | xargs kill -9

Ambos os processos são eliminados ao executar isso localmente. Mas ao usá-lo com ssh como

ssh foo@<IP Address> "ps -ef | grep foo | grep -v grep | awk {'print $2'} | xargs kill -9"

apenas um PID de dois está sendo excluído. Emite kill: <PID>: No such process . Poderia estar tentando matar o segundo processo localmente?

    
por Steve 09.03.2016 / 00:16

2 respostas

7

O $2 está entre aspas duplas na linha de comando do shell local, então é expandido pelo seu shell local (provavelmente para a string vazia).

Portanto, o comando executado no host remoto é algo como:

 ps -ef | grep foo | grep -v grep | awk {'print '} | xargs kill -9

Esse comando awk não funciona (imprime todas as linhas) e xargs será executado:

 kill -9 <all-the-words-present-in-the-output-of-ps|grep...>

Isso inclui pid e ppid, nomes de usuários ...

Além disso, se o comando pid do kill estiver nessa lista, ele se matará e, portanto, não conseguirá matar os restantes na lista.

Aqui, você deseja:

ssh foo@<IP Address> 'pkill -KILL -f foo'

(mata todos os processos cuja linha de comando (pelo menos os primeiros kilobytes dele) contém foo ).

Ou se o sistema remoto não tiver o comando pkill :

ssh foo@<IP Address> '
  ps -eo pid= -o args= |
    awk "/[f]oo/ {print \}" |
    xargs kill -s KILL'

Usamos aspas simples no lado local (portanto, nenhuma expansão de variável lá) e aspas duplas para a linha de comando do shell remoto, portanto, precisamos escapar do $ in $1 para que ele não seja expandido pelo shell remoto.

awk é um superconjunto de grep , você geralmente não precisa juntá-los. O melhor é dizer a ps para produzir apenas as coisas que você quer combinar, aqui assumindo que você quer procurar por foo na lista de argumentos mostrada por ps como seu uso de -f sugere.

Se você quiser matar todos os processos do usuário remoto (aqui do usuário foo e sshing como foo), você poderia fazer:

 ssh foo@<IP Address> 'kill -s KILL -- -1'

Isso eliminará todos os processos que o usuário tem permissão para matar. Para um usuário normal, são todos os processos cujo ID de usuário definido real ou salvo é o mesmo que o ID de usuário real ou efetivo do processo de eliminação.

Ou:

 ssh foo@<IP Address> 'pkill -KILL -U "$(id -u)"'

(ou pkill -U foo ). Para matar todos os processos cujo ID de usuário real é o mesmo que o ID de usuário efetivo do usuário remoto.

Ou você poderia fazer:

 ssh foo@<IP Address> '
   trap "" HUP
   ps -eo sid= -o pid= -U "$(id -u)" |
     awk "\ != $(ps -eo sid= -p "\$\$") {print \}" |
     xargs kill -s KILL'

(verificando em sid para que kill não se mate, o shell, awk ou xargs e ignorando SIGHUP no caso de matar o usuário sshd processo faz com que esse sinal seja enviado)

Estamos assumindo que o shell de login do usuário remoto é semelhante ao Bourne. Esses comandos teriam que ser adaptados se o shell de login do usuário remoto for das famílias csh ou rc que possuem uma sintaxe diferente, por exemplo.

Também é melhor referir-se aos sinais pelo nome em vez do número, o que torna mais claro e o número do sinal pode mudar de sistema para sistema (9 para o SIGKILL é bastante universal).

    
por 09.03.2016 / 12:43
3

tente isso resumidamente

 ssh user_name@ip_address "pkill -9 foo"

ou se você quiser um longo

 ssh user_name@ip_address "ps aux | grep '[f]oo' | awk '{print \"kill -9 \"\}' | bash -v"
    
por 09.03.2016 / 12:10