ssh komutu ssh sona erdikten sonra diğer sistemde beklenmedik şekilde devam ediyor


11

Aşağıdaki komutu çalıştırıyorum ve diğer sistemdeki çıktı dosyasını izliyorum:

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

Eğer ssh komutunu kullanarak ^Cveya oturum açtığım terminali öldürerek öldürürsem, uzak komutun da sonlanmasını beklerdim. Ancak bu gerçekleşmez: /tmp/countne olursa olsun tüm sayıları 1-5 alır ve ps -ejHkabuğu ve sleepçocuğunun çalışmaya devam ettiğini gösterir .

Bu beklenen davranış mı ve herhangi bir yerde belgelenmiş mi? Devre dışı bırakabilir miyim? Etrafta okurken, bu tür davranışları varsayılan olarak değil, nohup ile açıkça etkinleştirmek zorunda kalacaktım.

Ssh ve sshd için man sayfalarına baktım, ancak belirgin bir şey tespit etmedim ve Google beni bu davranışı kapatmak için değil, bu davranışı kapatmak için talimatlara yönlendirdi.

Her iki sistemde de root girişi ve bash kabuğu ile Red Hat Enterprise Linux 6.2 kullanıyorum.

Yanıtlar:


11

uther'ın cevabı size bir terminal tahsis etmenizi söyler ancak nedenini açıklamaz. Nedeni ssh'a özgü değildir, sinyal üretimi ve yayılması meselesidir. Sizi çeşitli sinyallerin gönderilmesine ne sebep olur? daha fazla arka plan için.

Uzak ana bilgisayarda, ilgili iki işlem vardır:

  • sshduzak programın giriş ve çıkışını yerel terminale geçiren bir ssh daemon ( ) örneği ;
  • o fordöngüyü çalıştıran bir kabuk .

Kabuk, döngünün sonuna ulaştığında veya ölümcül bir hatayla karşılaştığında doğal olarak ölebilir veya bir sinyale dönüşebilir. Soru, kabuk neden bir sinyal alacak?

Uzak kabuk, sshdborulara bağlanırsa , sshkomut satırında bir komut belirttiğinizde olan şey budur , eğer çıkar ve kabuk boruya yazmaya çalışırsa SIGPIPE'den ölür sshd. Kabuk boruya yazmadıkça, SIGPIPE almaz. Burada, kabuk asla standart çıktısına hiçbir şey yazmaz, böylece sonsuza kadar yaşayabilir.

-tUzak taraftaki bir terminali taklit etmesini ve bu terminalde belirtilen komutu çalıştırmasını söylemek için ssh seçeneğine geçebilirsiniz . Ardından, SSH istemcisi kaybolursa, sshdbağlantıyı kapatır ve terminali yok ederek çıkar. Terminal cihazı gittiğinde, içinde çalışan herhangi bir işlem bir SIGHUP alır . Bu nedenle, SSH istemcisini öldürürseniz ( killistemcinin çalıştığı terminalle veya terminali kapatarak), uzak kabuk SIGHUPped olur.

-tSeçeneği geçerseniz , SSH ayrıca SIGINT'i de iletir . Ctrl+ Tuşuna basarsanız C, uzak kabuk SIGINT alır.


Kullanım -ttyerine -tssh kendisi tahsis TTY yoksa. SSH -fveya gibi seçenekler aracılığıyla çağrıldıktan hemen sonra arka plana alınırsa SSH tahsis edilmez -n.
Miron V

3

sshKomutunuzla birlikte bir psuedo-tty ayırmayı deneyin .

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

Ssh oturumunun bağlantısını kestiğinizde, işlem sonlandırılmalıdır.

Bu sözde bir tty olduğundan, kabuk başlatma işleminiz büyük olasılıkla kaynak yapılandırma dosyalarına gitmeyecek ve komutunuzu çok çıplak bir ortama bırakacaktır. .ssh/environmentPATH gibi ortam değişkenlerini tanımlayan bir dosya ayarlamanız gerekebilir . itibarenman 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).

2

İstemci çıktığında veya (öldürüldüğünde) uzak komutun sona erdirilmesi -tseçeneğini kullanmanın bir alternatifi olarak , adı verilen bilgisayar kapalıyken "EOF'u SIGHUP'a dönüştürmek için adlandırılmış bir boru kullanılabilir (bkz. Hata 396 - sshd pty tahsis edilmediğinde yetimler işlenir ).sshsshsshd

# 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"
'

1

Bunu yapmanın en iyi yolu bu. Sunucu tarafında stdin okumaya çalışan ve daha sonra bu başarısız olduğunda işlem grubunu öldüren bir şey istersiniz, ancak istemci tarafında sunucu tarafı işlemi tamamlanıncaya kadar engelleyen ve < uyku sonsuz) olabilir.

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

Aslında stdout'u hiçbir yere yönlendirmiyor gibi görünüyor, ancak engelleme girişi olarak işlev görüyor ve tuş vuruşlarını yakalamayı önlüyor.

İlgili açık hata: https://bugzilla.mindrot.org/show_bug.cgi?id=396#c14


0

Bunu devre dışı bırakmak istiyorsanız (görünüşte varsayılan davranış) , istemci veya sunucu tarafında ssh-keep-alive'yi etkinleştirmeniz gerekir .

Man-sayfalarındaki ssh-keep-alive-seçeneklerine bakarsanız, bunların varsayılan olarak devre dışı bırakıldığını görebilirsiniz.


0

Cevabım teru'ya dayanıyor. ~/helperSunucu server.ip bir yardımcı komut dosyası gerekir :

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

Eğer örneğin

ssh server.ip ~/helper echo hello from server

ve echo hello from serverserver.ip dosyasında çalışır ve ssh istemcisi sonlanır.

Eğer örneğin

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

kill -9 $CHIDkomut dosyasını sunucuda da durduracaktır. Benim kill -INT $CHIDiçin çalışmıyor, ama nedenini bilmiyorum.

Teru'nun cevabında, ssh komutu uzak komut tamamlandığında sonsuza kadar bekler, çünkü catasla bitmez.

Ssh -t ile olan tüm cevaplar benim için değil kill, sadece Ctrl-C ile çalıştı.

Düzenleme: Bu yeni bir Ubuntu 14.01 yaşlı bir bilimsel linux kutusuna çalıştı öğrendim - ama başka bir şekilde değil. Dolayısıyla genel bir çözüm olmadığını düşünüyorum. Tuhaf.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.