Twoje przypuszczenie, że to on ssh
sam zwraca kod wyjścia 255, jest prawidłowe. Thessh
Strona mężczyzna stwierdza, że:
ssh kończy pracę ze statusem wyjścia polecenia zdalnego lub z 255, jeśli wystąpił błąd.
Jeśli po prostu ssh [email protected] "pkill -f asdf"
chcesz uruchomić , najprawdopodobniej uzyskasz status wyjścia 1
odpowiadający pkill
statusowi „ Brak dopasowanych procesów ”.
Wyzwaniem jest zrozumienie, dlaczego podczas uruchamiania występuje błąd SSH
ssh pi@10.20.0.10 "pkill -f asdf || true"
Zdalne polecenia SSH
Serwer SSH uruchamia powłokę w celu uruchomienia zdalnych poleceń. Oto przykład tego w akcji:
$ 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
Zauważ, że domyślną powłoką jest bash
i że zdalne polecenie nie jest prostym poleceniem, lecz potokiem , „sekwencją jednego lub więcej poleceń oddzielonych przez operatora sterującego|
”.
Powłoka Bash jest na tyle sprytna, aby zdać sobie sprawę, że jeśli polecenie przekazane do niej przez -c
opcję jest prostym poleceniem , można je zoptymalizować, nie wykonując nowego procesu, tj. Bezpośrednio exec
jest to proste polecenie zamiast przejść przez dodatkowy krok z fork
ing zanim exec
s. Oto przykład tego, co dzieje się po uruchomieniu zdalnej prostej komendy ( ps -elf
w tym przypadku):
$ 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
Zetknąłem się z tym już wcześniej, ale nie mogłem znaleźć lepszego źródła niż ta odpowiedź AskUbuntu .
zachowanie pkill
Ponieważ pkill -f asdf || true
nie jest to proste polecenia (jest to lista poleceń ), powyższe optymalizacja nie może nastąpić po uruchomieniu tak ssh [email protected] "pkill -f asdf || true"
, te sshd
widły procesowych i execsbash -c "pkill -f asdf || true"
.
Jak wskazuje odpowiedź ctx, pkill
nie zabije własnego procesu. Jednak to będzie zabić jakiegokolwiek innego procesu, którego linia poleceń pasuje do -f
wzorca. bash -c
Komenda pasuje ten wzorzec tak zabija ten proces - własnego rodzica (jak to się dzieje).
Serwer SSH następnie widzi, że proces powłoki, który uruchomił w celu uruchomienia poleceń zdalnych, został nieoczekiwanie zabity, więc zgłasza błąd klientowi SSH.
pkill
zabijającego proces powłoki nadrzędnej, ponieważ jego lista argumentów jest zgodna z wyrażeniem regularnym, podniosę zastrzeżenie terminologiczne:x || y
to nie jest złożone polecenie , to lista poleceń .x||y
jako listy poleceń. Zmodyfikowałem teraz moją odpowiedź, aby uwzględnić łącza do różnych definicji POSIX.zsh
/ksh93
/ FreeBSDsh
,false || pkill -f asdf
byłbypkill
wykonany w procesie powłoki.bash
wykonuje optymalizację tylko wtedy, gdy jest tylko jedno proste polecenie.true; pkill -f asdf
byłby również problem.Twoje zdalne polecenie zabija się:
pgrep i pkill zignorują własny proces, ale przy opcji -f znajdą powłokę nadrzędną:
źródło
bash -c 'pgrep -af asdf'
(bez|| true
) nie znajdzie się. Dlaczego nie? Ma-f
.Pytasz pkill, aby zabił wszystko, co pasowało do „asdf”. Powinieneś powiedzieć mu, aby pasował do [a] sdf, w ten sposób będzie nadal szukał czegoś o nazwie „asdf”, ale nie zobaczy siebie (jeśli wyrównasz asdf z [a] sdf, zwróć uwagę, że s jest wyrównany z] i nie s.)
Jest to powszechna sztuczka stosowana również w grep / egrep / awk / etc:
Ta sztuczka jest stara i widziałem ją kilkadziesiąt lat temu w Uniksowym FAQ (który wciąż jest dobrą lekturą!)
Aby go „zautomatyzować”, nie jest to łatwe, ale zwykle za każdym razem, gdy potrzebujesz grep dla zmiennej zmiennej regexp = "coś", możesz spróbować:
źródło
(abc)?(def)?
tym musisz być([a]bc)?([d]ef)?
... Nie możesz parsować wyrażeń regularnych z wyrażeniami regularnymi ?! > :-)