Sua suposição de que é ela ssh
mesma que retorna o status de saída 255 está correta. A ssh
página do manual afirma que:
O ssh sai com o status de saída do comando remoto ou com 255 se ocorreu um erro.
Se você simplesmente executasse ssh [email protected] "pkill -f asdf"
, provavelmente obteria um status de saída 1
correspondente ao pkill
status de " Nenhum processo correspondido ".
A parte desafiadora é entender por que ocorre um erro no SSH quando você executa
ssh pi@10.20.0.10 "pkill -f asdf || true"
Comandos remotos SSH
O servidor SSH inicia um shell para executar comandos remotos. Aqui está um exemplo disso em ação:
$ ssh server "ps -elf | tail -5"
4 S root 35323 1024 12 80 0 - 43170 poll_s 12:01 ? 00:00:00 sshd: anthony [priv]
5 S anthony 35329 35323 0 80 0 - 43170 poll_s 12:01 ? 00:00:00 sshd: anthony@notty
0 S anthony 35330 35329 0 80 0 - 28283 do_wai 12:01 ? 00:00:00 bash -c ps -elf | tail -5
0 R anthony 35341 35330 0 80 0 - 40340 - 12:01 ? 00:00:00 ps -elf
0 S anthony 35342 35330 0 80 0 - 26985 pipe_w 12:01 ? 00:00:00 tail -5
Observe que o shell padrão é bash
e que o comando remoto não é um comando simples, mas um pipeline , “uma sequência de um ou mais comandos separados pelo operador de controle |
”.
O shell Bash é inteligente o suficiente para perceber que, se o comando que está sendo passado pela -c
opção for um comando simples , ele pode otimizar não sendo realmente bifurcado em um novo processo, ou seja, é diretamente exec
o comando simples em vez de passar pela etapa extra de fork
ing antes que ele exec
é. Aqui está um exemplo do que acontece quando você executa um comando simples remoto ( ps -elf
neste caso):
$ ssh server "ps -elf" | tail -5
1 S root 34740 2 0 80 0 - 0 worker 11:49 ? 00:00:00 [kworker/0:1]
1 S root 34762 2 0 80 0 - 0 worker 11:50 ? 00:00:00 [kworker/0:3]
4 S root 34824 1024 31 80 0 - 43170 poll_s 11:51 ? 00:00:00 sshd: anthony [priv]
5 S anthony 34829 34824 0 80 0 - 43170 poll_s 11:51 ? 00:00:00 sshd: anthony@notty
0 R anthony 34830 34829 0 80 0 - 40340 - 11:51 ? 00:00:00 ps -elf
Já deparei com esse comportamento antes, mas não consegui encontrar uma referência melhor além desta resposta do AskUbuntu .
comportamento pkill
Como pkill -f asdf || true
não é um comando simples (é uma lista de comandos ), a otimização acima pode não ocorrer; portanto, quando você executa ssh [email protected] "pkill -f asdf || true"
, o sshd
processo bifurca e executa bash -c "pkill -f asdf || true"
.
Como a resposta da ctx aponta, pkill
não matará seu próprio processo. No entanto, ele vai matar qualquer outro processo cuja linha de comando corresponde ao -f
padrão. O bash -c
comando corresponde a esse padrão e mata esse processo - seu próprio pai (por acaso).
O servidor SSH vê, então, que o processo do shell iniciado para executar os comandos remotos foi interrompido inesperadamente e, portanto, relata um erro ao cliente SSH.
pkill
mata seu processo de shell pai porque sua lista arg corresponde ao regexp, levantarei uma objeção terminológica: nãox || y
é um comando composto , é uma lista de comandos .x||y
uma lista de comandos. Agora editei minha resposta para incluir links para as várias definições de POSIX.zsh
/ksh93
/ FreeBSDsh
,false || pkill -f asdf
teria sidopkill
executado no processo do shell.bash
só faz a otimização quando há apenas um comando simples.true; pkill -f asdf
também seria um problema.Seu comando remoto se mata:
O pgrep e o pkill ignoram seu próprio processo, mas com o sinalizador -f, eles encontrarão o shell pai:
fonte
bash -c 'pgrep -af asdf'
(sem o|| true
) não se encontra. Por que não? Tem-f
.Você pede ao pkill para matar qualquer coisa que corresponda a "asdf". Você deve dizer para ele corresponder a [a] sdf, para que ainda procure por qualquer coisa chamada "asdf", mas não se veja (se você alinhar asdf com [a] sdf, observe que s está alinhado com] e não s.)
É um truque comum também usado com grep / egrep / awk / etc:
Esse truque é antigo, e eu o vi décadas atrás no FAQ do Unix (que ainda é uma boa leitura!)
Para "automatizá-lo", não é fácil, mas geralmente toda vez que você precisa grep para uma sequência variável regexp = "something", você pode tentar fazer:
fonte
(abc)?(def)?
terá que ser([a]bc)?([d]ef)?
... Você não pode analisar regex com regex ?! > :