Quando provo a eseguire pkill -f
in remoto tramite ssh e prova a scartare il possibile codice di errore (per continuare con il resto del mio script anche se non viene trovato alcun processo), || true
non si comporta come mi aspetto.
$ pkill asdf || true
$ echo $?
0
$ pkill -f asdf || true
$ echo $?
0
$ ssh [email protected] "pkill asdf || true"
$ echo $?
0
$ ssh [email protected] "pkill -f asdf || true"
255
Suppongo che sia ssh che restituisce 255, non il comando tra virgolette, ma perché?
Risposta accettata:
La tua supposizione che sia ssh
stesso che restituisce lo stato di uscita 255 è corretto. Il ssh
la pagina man afferma che:
ssh esce con lo stato di uscita del comando remoto o con 255 se si è verificato un errore.
Se dovessi eseguire semplicemente ssh [email protected] "pkill -f asdf"
, molto probabilmente otterrai uno stato di uscita di 1
, corrispondente al pkill
stato per "Nessun processo corrispondente ”.
La parte difficile è capire perché si verifica un errore con SSH durante l'esecuzione
ssh [email protected] "pkill -f asdf || true"
Comandi remoti SSH
Il server SSH avvia una shell per eseguire i comandi remoti. Ecco un esempio in azione:
$ 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: [email protected]
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
Nota che la shell predefinita è bash
e che il comando remoto non è un semplice comando ma una pipeline, “una sequenza di uno o più comandi separati dall'operatore di controllo |
”.
La shell Bash è abbastanza intelligente da rendersi conto che se il comando le viene passato dal -c
l'opzione è un semplice comando, può ottimizzare non effettuando effettivamente il fork di un nuovo processo, cioè direttamente exec
s il semplice comando invece di passare attraverso il passaggio aggiuntivo di fork
prima di esso exec
S. Ecco un esempio di cosa succede quando esegui un comando semplice remoto (ps -elf
in questo 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: [email protected]
0 R anthony 34830 34829 0 80 0 - 40340 - 11:51 ? 00:00:00 ps -elf
Mi sono imbattuto in questo comportamento in precedenza, ma non sono riuscito a trovare un riferimento migliore oltre a questa risposta di AskUbuntu.
Correlati:qual è la differenza tra punto e virgola e doppia e&&?comportamento dell'uccisione
Poiché pkill -f asdf || true
non è un semplice comando (è un elenco di comandi), l'ottimizzazione di cui sopra non può verificarsi quindi quando esegui ssh [email protected] "pkill -f asdf || true"
, il sshd
process fork ed exec bash -c "pkill -f asdf || true"
.
Come sottolinea la risposta di ctx, pkill
non ucciderà il proprio processo. Tuttavia, lo farà kill qualsiasi altro processo la cui riga di comando corrisponda a -f
modello. Il bash -c
il comando corrisponde a questo modello, quindi uccide questo processo:il suo genitore (come succede).
Il server SSH vede quindi che il processo di shell avviato per eseguire i comandi remoti è stato interrotto in modo imprevisto, quindi segnala un errore al client SSH.