Když se pokusím spustit pkill -f
vzdáleně přes ssh a pokusit se zahodit možný chybový kód (abych mohl pokračovat se zbytkem mého skriptu, i když nebyl nalezen žádný proces), || true
se nechová tak, jak očekávám.
$ 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
Předpokládám, že je to ssh to vrátí 255, ne příkaz mezi uvozovkami, ale proč?
Přijatá odpověď:
Váš předpoklad, že je to ssh
sám, který vrací 255 návratový stav, je správný. ssh
manuálová stránka uvádí, že:
ssh se ukončí se stavem ukončení vzdáleného příkazu nebo s 255, pokud došlo k chybě.
Pokud byste jednoduše spustili ssh [email protected] "pkill -f asdf"
, s největší pravděpodobností dostanete stav ukončení 1
, což odpovídá pkill
stav pro „Neodpovídají žádné procesy “.
Náročnou částí je pochopit proč při spuštění dojde u SSH k chybě
ssh [email protected] "pkill -f asdf || true"
Vzdálené příkazy SSH
SSH server spustí shell pro spuštění vzdálených příkazů. Zde je příklad toho v akci:
$ 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
Všimněte si, že výchozí shell je bash
a že vzdálený příkaz není jednoduchý příkaz, ale kanál, „sekvence jednoho nebo více příkazů oddělených řídicím operátorem |
“.
Shell Bash je dostatečně chytrý na to, aby si uvědomil, že pokud je mu příkaz předán pomocí -c
volba je jednoduchý příkaz, může se optimalizovat tím, že ve skutečnosti neforkuje nový proces, tj. přímo exec
Je to jednoduchý příkaz namísto procházení dalším krokem fork
ing před tím exec
s. Zde je příklad toho, co se stane, když spustíte vzdálený jednoduchý příkaz (ps -elf
v tomto případě):
$ 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
S tímto chováním jsem se již setkal dříve, ale nemohl jsem najít lepší referenci než tuto odpověď AskUbuntu.
Související:Jaký je rozdíl mezi středníkem a dvojitým a&&?pkill chování
Protože pkill -f asdf || true
není jednoduchý příkaz (je to seznam příkazů), výše uvedená optimalizace nemůže nastat, takže když spustíte ssh [email protected] "pkill -f asdf || true"
, sshd
proces forks a execs bash -c "pkill -f asdf || true"
.
Jak ukazuje odpověď ctx, pkill
nezabije svůj vlastní proces. Nicméně bude zabít jakýkoli jiný proces, jehož příkazový řádek odpovídá -f
vzor. bash -c
příkaz odpovídá tomuto vzoru, takže zabije tento proces – jeho vlastního rodiče (jak se to stane).
SSH server pak vidí, že proces shellu, který spustil za účelem spouštění vzdálených příkazů, byl neočekávaně zabit, takže ohlásí chybu klientovi SSH.