Ihre Annahme, dass es sich ssh
selbst handelt, der den Exit-Status 255 zurückgibt, ist korrekt. In der ssh
Manpage heißt es:
ssh wird mit dem Exit-Status des Remote-Befehls oder mit 255 beendet, wenn ein Fehler aufgetreten ist.
Wenn Sie einfach ausführen würden ssh [email protected] "pkill -f asdf"
, würden Sie höchstwahrscheinlich einen Beendigungsstatus von erhalten 1
, der dem pkill
Status für " Keine Prozesse gefunden " entspricht.
Die Herausforderung besteht darin, zu verstehen, warum bei der Ausführung von SSH ein Fehler auftritt
ssh pi@10.20.0.10 "pkill -f asdf || true"
SSH-Fernbefehle
Der SSH-Server startet eine Shell zum Ausführen von Remote-Befehlen. Hier ist ein Beispiel dafür in Aktion:
$ 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
Beachten Sie, dass die Standard-Shell ist bash
und dass der Remote-Befehl kein einfacher Befehl, sondern eine Pipeline ist , „eine Folge von einem oder mehreren Befehlen, die vom Steueroperator getrennt werden|
".
Die Bash - Shell klug genug , um zu erkennen , dass , wenn der Befehl von der an sie übergeben werden -c
Option ist ein einfacher Befehl , es durch nicht wirklich Forking einen neuen Prozess zu optimieren, das heißt, es direkt exec
s den einfachen Befehl statt durch den zusätzlichen Schritt des Gehens von fork
ing , bevor es exec
s. Hier ist ein Beispiel dafür, was passiert, wenn Sie einen einfachen Remote-Befehl ausführen ( ps -elf
in diesem Fall):
$ 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
Ich habe dieses Verhalten schon einmal erlebt, konnte aber keine bessere Referenz als diese AskUbuntu-Antwort finden .
Pkill-Verhalten
Da pkill -f asdf || true
es sich nicht um einen einfachen Befehl handelt (es handelt sich um eine Befehlsliste ), kann die oben genannte Optimierung nicht durchgeführt werden. Wenn Sie diesen Befehl ausführen ssh [email protected] "pkill -f asdf || true"
, wird er vom sshd
Prozess gegabelt und ausgeführt bash -c "pkill -f asdf || true"
.
Wie die Antwort von ctx zeigt, pkill
wird es seinen eigenen Prozess nicht beenden. Es wird jedoch jeder andere Prozess beendet, dessen Befehlszeile dem -f
Muster entspricht. Der bash -c
Befehl stimmt mit diesem Muster überein, sodass er diesen Prozess abbricht - seinen eigenen übergeordneten Prozess (wie es geschieht).
Der SSH-Server stellt dann fest, dass der Shell-Prozess, den er zum Ausführen der Remotebefehle gestartet hat, unerwartet beendet wurde, sodass ein Fehler an den SSH-Client gemeldet wird.
pkill
beim Beenden des übergeordneten Shell-Prozesses der Fall ist, weil die Argumentliste mit dem regulären Ausdruck übereinstimmt, werde ich einen terminologischen Einwand erheben: Esx || y
handelt sich nicht um einen zusammengesetzten Befehl , sondern um eine Befehlsliste .x||y
als Befehlsliste zu betrachten . Ich habe meine Antwort jetzt so bearbeitet, dass sie Links zu den verschiedenen POSIX-Definitionen enthält.zsh
/ksh93
/ FreeBSDsh
,false || pkill -f asdf
wärepkill
in dem Shell - Prozess ausgeführt.bash
Die Optimierung wird nur ausgeführt, wenn nur ein einfacher Befehl vorhanden ist.true; pkill -f asdf
wäre auch ein problem.Ihr Remote-Befehl bringt sich selbst um:
pgrep und pkill ignorieren ihren eigenen Prozess, aber mit dem Flag -f finden sie die übergeordnete Shell:
quelle
bash -c 'pgrep -af asdf'
(ohne die|| true
) findet sich nicht . Warum nicht? Es hat-f
.Sie bitten pkill, alles zu töten, was mit "asdf" übereinstimmt. Sie sollten festlegen, dass es mit [a] sdf übereinstimmt. Auf diese Weise sucht es weiterhin nach "asdf", sieht sich jedoch nicht selbst (wenn Sie asdf an [a] sdf ausrichten, beachten Sie, dass das s an] und ausgerichtet ist nicht s.)
Dies ist ein allgemeiner Trick, der auch mit grep / egrep / awk / etc verwendet wird:
Dieser Trick ist alt und ich habe ihn vor Jahrzehnten in der Unix-FAQ gesehen (was immer noch eine gute Lektüre ist!)
Um es zu "automatisieren", ist es nicht einfach, aber normalerweise können Sie versuchen, jedes Mal, wenn Sie nach einer variablen Zeichenfolge regexp = "something" suchen, Folgendes zu tun:
quelle
(abc)?(def)?
muss es sein([a]bc)?([d]ef)?
... Sie können Regex nicht mit Regex analysieren ?! > :-)