Perintah ssh tiba-tiba berlanjut di sistem lain setelah ssh berakhir

11

Saya menjalankan perintah di bawah ini, dan memonitor file output di sistem lain:

ssh $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

Jika saya mematikan perintah ssh menggunakan ^Catau dengan hanya membunuh terminal saya login, saya akan mengharapkan perintah jarak jauh untuk mengakhiri juga. Ini tidak terjadi, meskipun: /tmp/countdapatkan semua angka 1-5 terlepas, dan ps -ejHmenunjukkan cangkang dan sleepanaknya terus berjalan.

Apakah ini perilaku yang diharapkan, dan apakah itu didokumentasikan di mana saja? Bisakah saya menonaktifkannya? Dari membaca sekitar, saya diharapkan untuk secara eksplisit mengaktifkan perilaku semacam ini dengan nohup, bukan untuk itu menjadi default.

Saya telah melihat-lihat halaman manual untuk ssh dan sshd, tetapi tidak menemukan sesuatu yang jelas, dan Google menunjuk saya pada instruksi untuk mengaktifkan perilaku ini, bukan untuk mematikannya.

Saya menjalankan Red Hat Enterprise Linux 6.2, dengan login root dan bash shell di kedua sistem.

saya dan
sumber

Jawaban:

11

Jawaban uther memberi tahu Anda untuk mengalokasikan terminal tetapi tidak menjelaskan alasannya. Alasannya tidak spesifik untuk ssh, ini adalah masalah generasi sinyal dan propagasi. Saya mengundang Anda untuk membaca Apa yang menyebabkan berbagai sinyal dikirim? untuk latar belakang lebih lanjut.

Pada host jarak jauh, ada dua proses yang relevan:

  • turunan dari ssh daemon ( sshd), yang menyampaikan input dan output dari program jarak jauh ke terminal lokal;
  • sebuah shell, yang menjalankan forloop itu.

Shell dapat mati secara alami ketika mencapai ujung loop atau mengalami kesalahan fatal, atau sinyal. Pertanyaannya adalah, mengapa shell menerima sinyal?

Jika shell jarak jauh terhubung ke sshdlebih dari pipa, yang adalah apa yang terjadi ketika Anda menentukan perintah pada sshbaris perintah, maka itu akan mati karena SIGPIPE jika sshdkeluar dan shell mencoba menulis ke pipa. Selama shell tidak menulis ke pipa, ia tidak akan menerima SIGPIPE. Di sini, shell tidak pernah menulis apa pun ke output standarnya, sehingga ia dapat hidup selamanya.

Anda dapat meneruskan -topsi ke ssh, untuk mengatakannya untuk meniru terminal pada sisi jarak jauh dan menjalankan perintah yang ditentukan di terminal ini. Kemudian, jika klien SSH menghilang, sshdtutup koneksi dan keluar, hancurkan terminal. Ketika perangkat terminal hilang, setiap proses yang berjalan di dalamnya menerima SIGHUP . Jadi, jika Anda membunuh klien SSH (dengan kill, atau dengan menutup terminal yang menjalankan klien), shell jarak jauh SIGHUP.

Jika Anda melewati -topsi, SSH juga relay SIGINT . Jika Anda menekan Ctrl+ C, maka shell jarak jauh menerima SIGINT.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Gunakan -ttsebagai ganti -tjika ssh itu sendiri tidak memiliki alokasi tty. SSH tidak akan mendapatkan tty yang dialokasikan jika ssh mendapatkan latar belakang segera setelah pemanggilan melalui opsi seperti -fatau -n.
Miron V
3

Coba alokasikan psuedo-tty dengan sshperintah Anda .

ssh -t $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

Ketika Anda memutuskan sesi ssh, prosesnya harus berakhir.

Karena ini adalah pseudo-tty, inisialisasi shell Anda mungkin tidak akan mencari file konfigurasi, meninggalkan perintah Anda dengan lingkungan yang sangat kosong. Anda mungkin perlu mengatur .ssh/environmentfile yang mendefinisikan variabel lingkungan seperti PATH. Dariman 1 ssh

Additionally, ssh reads ~/.ssh/environment, and adds lines of the format 
“VARNAME=value” to the environment if the file exists and users are allowed
to change their environment.  For more information, see the 
PermitUserEnvironment option in sshd_config(5).
George M.
sumber
2

Sebagai alternatif untuk menggunakan -topsi untuk sshmembuat perintah jarak jauh berakhir ketika sshklien keluar atau (terbunuh), pipa bernama dapat digunakan untuk mengubah "EOF ke SIGHUP" ketika stdin sshdsedang ditutup (lihat Bug 396 - sshd yatim piatu memproses bila tidak ada pty yang dialokasikan ).

# sample code in Bash
# press ctrl-d for EOF
ssh localhost '
TUBE=/tmp/myfifo.fifo
rm -f "$TUBE"
mkfifo "$TUBE"
#exec 3<>"$TUBE"

<"$TUBE" sleep 100 &  appPID=$!

# cf. "OpenSSH and non-blocking mode", 
# http://lists.mindrot.org/pipermail/openssh-unix-dev/2005-July/023090.html
#cat >"$TUBE"
#socat -u STDIN "PIPE:$TUBE"
dd of="$TUBE" bs=1 2>/dev/null
#while IFS="" read -r -n 1 char; do printf '%s' "$char"; done > "$TUBE"

#kill -HUP -$appPID 
kill $appPID

rm -f "$TUBE"
'
teru
sumber
1

Ini adalah cara terbaik yang saya temukan untuk melakukan ini. Anda menginginkan sesuatu di sisi server yang mencoba membaca stdin dan kemudian membunuh grup proses ketika itu gagal, tetapi Anda juga ingin stdin di sisi klien yang memblokir sampai proses sisi server dilakukan dan tidak akan meninggalkan proses yang tersisa seperti <( sleep infinity) mungkin.

ssh localhost "sleep 99 < <(cat; kill -INT 0)" <&1

Tampaknya tidak mengarahkan stdout di mana pun tetapi berfungsi sebagai input pemblokiran dan menghindari penekanan tombol.

Bug openssh yang relevan: https://bugzilla.mindrot.org/show_bug.cgi?id=396#c14

Eric Woodruff
sumber
0

Jika Anda ingin menonaktifkan itu (kelihatannya perilaku default), Anda perlu mengaktifkan ssh-keep-hidup di sisi klien atau server.

Jika Anda melihat opsi ssh-keep-hidup-di halaman manual, Anda dapat melihat bahwa mereka dinonaktifkan secara default.

Nils
sumber
0

Jawaban saya didasarkan pada teru. Saya memerlukan skrip pembantu ~/helperdi server server.ip:

#!/bin/bash
TUBE=/tmp/sshCoLab_myfifo.$$;
mkfifo "$TUBE"
( <"$TUBE" "$@" ; rm "$TUBE" ; kill -TERM 0 ) &  
cat >"$TUBE" ;
rm "$TUBE" ;
kill -TERM 0 ;

Jika itu disebut misalnya dengan

ssh server.ip ~/helper echo hello from server

dan dijalankan echo hello from serverdi server.ip, dan kemudian klien ssh akan berakhir.

Jika itu disebut misalnya dengan

ssh server.ip ~/helper sleep 1000 &
CHID=$!

kill -9 $CHIDakan menghentikan skrip di server juga. Bagi saya, kill -INT $CHIDtidak berhasil, tetapi saya tidak tahu mengapa.

Dalam jawaban teru, perintah ssh akan menunggu selamanya ketika perintah jarak jauh selesai, karena cattidak pernah selesai.

Semua jawaban dengan ssh -t tidak bekerja untuk saya kill, tetapi hanya dengan Ctrl-C.

Sunting: Saya menemukan ini bekerja dari Ubuntu 14,01 baru ke kotak linux ilmiah tua - tetapi tidak sebaliknya. Jadi, saya pikir tidak ada solusi umum. Aneh.

Peter Steier
sumber