Wenn ich versuche, pkill -f
auszuführen remote über ssh, und versuchen Sie, den möglichen Fehlercode zu verwerfen (um mit dem Rest meines Skripts fortzufahren, auch wenn kein Prozess gefunden wird), || true
verhält sich nicht wie erwartet.
$ 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
Ich nehme an, dass es ssh ist das gibt 255 zurück, nicht den Befehl zwischen Anführungszeichen, aber warum?
Akzeptierte Antwort:
Ihre Vermutung, dass es sich um ssh
handelt selbst, das den Exit-Status 255 zurückgibt, ist korrekt. Die ssh
man-Seite besagt, dass:
ssh beendet sich mit dem Exit-Status des Remote-Befehls oder mit 255, wenn ein Fehler aufgetreten ist.
Wenn Sie einfach ssh [email protected] "pkill -f asdf"
ausführen würden , erhalten Sie höchstwahrscheinlich einen Exit-Status von 1
, entsprechend dem pkill
Status für „Keine übereinstimmenden Prozesse “.
Der herausfordernde Teil besteht darin, warum zu verstehen Beim Ausführen von SSH tritt ein Fehler auf
ssh [email protected] "pkill -f asdf || true"
SSH-Remote-Befehle
Der SSH-Server startet eine Shell, um Remote-Befehle auszuführen. 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: [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
Beachten Sie, dass die Standard-Shell bash
ist und dass der Remote-Befehl kein einfacher Befehl, sondern eine Pipeline ist, „eine Folge von einem oder mehreren Befehlen, die durch den Kontrolloperator |
getrennt sind “.
Die Bash-Shell ist schlau genug, um zu erkennen, dass ihr der Befehl mit -c
übergeben wird Option ist ein einfacher Befehl, er kann optimieren, indem er nicht wirklich einen neuen Prozess forkt, d. h. direkt exec
s der einfache Befehl, anstatt den zusätzlichen Schritt von fork
zu durchlaufen ing davor 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: [email protected]
0 R anthony 34830 34829 0 80 0 - 40340 - 11:51 ? 00:00:00 ps -elf
Mir ist dieses Verhalten schon einmal begegnet, aber ich konnte keine bessere Referenz als diese AskUbuntu-Antwort finden.
Verwandte:Was ist der Unterschied zwischen Semikolon und doppeltem kaufmännischem Und &&?pkill-Verhalten
Da pkill -f asdf || true
kein einfacher Befehl ist (es ist eine Befehlsliste), kann die obige Optimierung nicht erfolgen, wenn Sie also ssh [email protected] "pkill -f asdf || true"
ausführen , die sshd
Process Forks und Execs bash -c "pkill -f asdf || true"
.
Wie die Antwort von ctx zeigt, pkill
wird seinen eigenen Prozess nicht beenden. Allerdings wird Beenden Sie alle anderen Prozesse, deren Befehlszeile mit -f
übereinstimmt Muster. Der bash -c
Der Befehl passt zu diesem Muster, sodass er diesen Prozess beendet – seinen eigenen Elternprozess (zufälligerweise).
Der SSH-Server sieht dann, dass der Shell-Prozess, den er gestartet hat, um die Remote-Befehle auszuführen, unerwartet beendet wurde, und meldet dem SSH-Client einen Fehler.