Anggapan Anda bahwa itu ssh
sendiri yang mengembalikan status keluar 255 adalah benar. The ssh
man page menyatakan bahwa:
ssh keluar dengan status keluar dari perintah jarak jauh atau dengan 255 jika terjadi kesalahan.
Jika Anda hanya menjalankan ssh [email protected] "pkill -f asdf"
, kemungkinan besar Anda akan mendapatkan status keluar 1
, sesuai dengan pkill
status untuk " Tidak ada proses yang cocok ".
Bagian yang menantang adalah untuk memahami mengapa kesalahan terjadi dengan SSH saat Anda menjalankan
ssh pi@10.20.0.10 "pkill -f asdf || true"
Perintah jarak jauh SSH
Server SSH meluncurkan shell untuk menjalankan perintah jarak jauh. Berikut ini contoh tindakan ini:
$ 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
Perhatikan bahwa shell default adalah bash
dan bahwa perintah jarak jauh bukan perintah sederhana tetapi sebuah pipa , "urutan satu atau lebih perintah yang dipisahkan oleh operator kontrol |
".
Bash shell cukup pintar untuk menyadari bahwa jika perintah yang diteruskan oleh -c
opsi tersebut adalah perintah sederhana , ia dapat mengoptimalkan dengan tidak benar-benar memalsukan proses baru, yaitu, ia secara langsung exec
merupakan perintah sederhana alih-alih melalui langkah tambahan dari fork
sebelum itu exec
s. Berikut adalah contoh dari apa yang terjadi ketika Anda menjalankan perintah sederhana jarak jauh ( ps -elf
dalam kasus ini):
$ 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
Saya telah menemukan perilaku ini sebelumnya tetapi saya tidak dapat menemukan referensi yang lebih baik selain jawaban AskUbuntu ini .
perilaku pkill
Karena pkill -f asdf || true
ini bukan perintah sederhana (ini daftar perintah ), optimasi di atas tidak dapat terjadi sehingga ketika Anda menjalankan ssh [email protected] "pkill -f asdf || true"
, sshd
proses bercabang dan mengeksekusi bash -c "pkill -f asdf || true"
.
Seperti yang ditunjukkan oleh jawaban ctx, pkill
tidak akan mematikan prosesnya sendiri. Namun, itu akan membunuh proses lain yang baris perintahnya sesuai dengan -f
pola. The bash -c
perintah sesuai dengan pola ini sehingga membunuh proses ini - induk sendiri (seperti yang terjadi).
Server SSH kemudian melihat bahwa proses shell itu dimulai untuk menjalankan perintah jarak jauh terbunuh secara tak terduga sehingga melaporkan kesalahan ke klien SSH.
pkill
membunuh proses shell induknya karena daftar arg yang cocok regexp, saya akan mengangkat keberatan terminologi:x || y
adalah tidak sebuah perintah senyawa , itu adalah daftar perintah .x||y
sebagai daftar perintah. Sekarang saya telah mengedit jawaban saya untuk memasukkan tautan ke berbagai definisi POSIX.zsh
/ksh93
/ FreeBSDsh
,false || pkill -f asdf
akanpkill
dieksekusi dalam proses shell.bash
hanya melakukan optimasi ketika hanya ada satu perintah sederhana.true; pkill -f asdf
juga akan menjadi masalah.Perintah jarak jauh Anda bunuh diri:
pgrep dan pkill akan mengabaikan proses mereka sendiri, tetapi dengan flag -f, mereka akan menemukan shell induk:
sumber
bash -c 'pgrep -af asdf'
(tanpa|| true
) tidak menemukan dirinya sendiri. Kenapa tidak? Sudah-f
.Anda meminta pkill untuk membunuh apa pun yang cocok dengan "asdf". Anda harus mengatakannya untuk mencocokkan [a] sdf, dengan cara itu ia akan tetap mencari apa pun yang bernama "asdf", tetapi tidak akan melihat dirinya sendiri (jika Anda menyelaraskan asdf dengan [a] sdf, perhatikan bahwa s selaras dengan] dan bukan s.)
Ini adalah trik umum yang juga digunakan dengan grep / egrep / awk / etc:
Trik ini sudah tua, dan saya melihatnya beberapa dekade yang lalu di faq Unix (yang masih bagus dibaca!)
Untuk "mengotomatisasi" itu, itu tidak mudah, tetapi biasanya setiap kali Anda perlu grep untuk string variabel regexp = "sesuatu", Anda dapat mencoba melakukan:
sumber
(abc)?(def)?
harus menjadi([a]bc)?([d]ef)?
... Anda tidak dapat mengurai regex dengan regex ?! > :-)