ssh üzerinde stderr -t


11

Bu, çıktıyı STDERR'a gönderir, ancak Ctrl+ çoğaltmaz C(yani Ctrl+ Cöldürür, sshancak uzaktan kumandayı öldürmez sleep):

$ ssh localhost 'sleep 100;echo foo ">&2"'

Bu Ctrl+ yayar C(yani Ctrl+ Cöldürür sshve uzaktan kumanda eder sleep), ancak STDERR'u STDOUT'a gönderir:

$ ssh -tt localhost 'sleep 100;echo foo ">&2"'

Ctrl+ ' Yı yaymaya devam ederken, ikincisini STDERR çıktısını STDERR'a göndermeye nasıl zorlayabilirim C?

Arka fon

GNU Parallel Ctrl+ 'yı yaymak için' ssh -tt 'kullanır C. Bu, uzaktan çalışan işleri öldürmeyi mümkün kılar. Ancak STDERR'a gönderilen veriler, alıcı uçta STDERR'a gitmeye devam etmelidir.

Yanıtlar:


5

Bunun üstesinden gelebileceğinizi sanmıyorum.

İle -tt, sshdbir sözde terminal oluşturur ve köle kısmını uzak komutu yürüten kabuğun stdin, stdout ve stderr'ı yapar.

sshd(tekli) fd'den sözde terminalin ana kısmına gelenleri okur ve bunu (tek bir kanal aracılığıyla) sshistemciye gönderir . Stderr için olduğu gibi ikinci bir kanal yoktur -t.

Ayrıca, sözde terminalin terminal hattı disiplininin çıkışı değiştirebileceğini (ve varsayılan olarak değiştireceğini) unutmayın. Örneğin, LF yerel terminalde değil orada CRLF'ye dönüştürülecektir, bu nedenle çıktı sonrası işlemeyi devre dışı bırakmak isteyebilirsiniz.

$ ssh  localhost 'echo x' | hd
00000000  78 0a                                             |x.|
00000002
$ ssh -t localhost 'echo x' | hd
00000000  78 0d 0a                                          |x..|
00000003
$ ssh -t localhost 'stty -opost; echo x' | hd
00000000  78 0a                                             |x.|
00000002

Giriş tarafında çok daha fazla şey olacak ( ^CSIGINT'e neden olacak karakter gibi , aynı zamanda diğer sinyaller, yankı ve kanonik mod satırı düzenleyicisine dahil olan tüm işlemler ).

Stderr'ı bir fifo'ya yönlendirebilir ve bir saniye kullanarak alabilirsiniz ssh:

ssh -tt host 'mkfifo fifo && cmd 2> fifo' &
ssh host 'cat fifo' >&2

Ancak en iyi IMO, -ttamamen kullanmaktan kaçınmak olacaktır . Bu gerçekten sadece gerçek bir terminalden etkileşimli kullanım içindir.

Uzak ucun bağlantının kapanmasına izin vermek için ^ C'nin iletimine güvenmek yerine poll(), öldürülen sshveya kapalı bağlantıyı algılamak için a yapan bir sargı kullanabilirsiniz .

Belki şöyle bir şey (basitleştirilmiş, bazı hata kontrolü eklemek isteyeceksiniz):

LC_HUP_DETECTOR='
  use IO::Poll;
  $SIG{CHLD} = sub {$done = 1};
  $p = IO::Poll->new;
  $p->mask(STDOUT, POLLIN);
  $pid=fork; unless($pid) {setpgrp; exec @ARGV; die "exec: $!\n"}
  $p->poll;
  kill SIGHUP, -$pid unless $done;
  wait; exit ($?&127 ? 128+($?&127) : 1+$?>>8)
' ssh host 'perl -e "$LC_HUP_DETECTOR" some cmd'

$p->mask(STDOUT, POLLIN)Yukarıdaki saçma görünebilir, ama fikir (kapalı olması stdout'ta borunun okuma sonda) bir asmak hup olay için beklemektir. İstenen maske olarak POLLHUP yoksayılır. POLLHUP yalnızca döndürülen olay olarak anlamlıdır ( yazma sonunun kapalı olduğunu söylemek için ).

Olay maskesi için sıfırdan farklı bir değer vermeliyiz. Eğer kullanırsak 0, perlaramaz bile poll. Burada POLLIN kullanıyoruz.

Linux'ta, ne istersen, boru bozulursa, anket () POLLERR döndürür.

Borunun okuma ucu (ayrıca bir yazı sonudur orada) kapalıdır borular çift yönlüdür Solaris ve FreeBSD, üzerinde, bu Pollin istemek zorunda FreeBSD üzerinde POLLHUP (ve Pollin ile döner veya başka $p->poll()yok dönüş).

Bu üç işletim sisteminin dışında ne kadar taşınabilir olduğunu söyleyemem.


Fikrinizi beğendim, ancak '-tt' ayarlanmadığı sürece ambalajınızın sinyalleri algılamasını sağlayamıyorum. Bu çalışır:, parallel --tag -j1 'ssh -tt localhost perl/catch_wrap perl/catch_all_signals & sleep 1; killall -{} ssh' ::: {1..31}ancak '-tt' öğesini kaldırın ve sonra çalışmaz.
Ole Tange

@OleTange Sargıcının amacı, ssh öldüğünde (ssh bağlantısı kapatıldığında) SIGHUP'un uzak işe gönderilmesidir. Senin catch_all_signals ne yaptığını bilmiyorum, ama tüm alacağı SIGHUP ve sadece ssh bağlantısı düştükten sonra (böylece stdout bir şey yazdırırsa, görmezsiniz).
Stéphane Chazelas

catch_all_signals tüm sinyalleri bir dosyaya kaydeder ve belirtildiği gibi '-tt' ile çalışır, ancak başarısız olur. Başka bir deyişle: ssh öldüğünde catch_wrap'tan SIGHUP almaz.
Ole Tange

Yine de yalnızca -ttdüzenlemenizden sonra çalışır . Komutu paralel olarak çalıştırmazsanız, ssh çalıştırdığınız terminali devralır.
Ole Tange

@OleTange, çoğaltamıyorum, benim için çalışıyor, gönderdiğim kodla test ettiniz mi? Bir göz atabilmek için lütfen catch_wrap ve catch_all_signals öğelerinizi bir yere gönderin. İle -t, bunu beklemek değil işe.
Stéphane Chazelas

1

Diğer platformlarda çalışmasını sağlamak için bu son çözüm oldu. Ssh istemcisinin bağlantısının kesilip kesilmediğini kontrol eder ve böylece ebeveyn pid 1 olur:

$SIG{CHLD} = sub { $done = 1; };
$pid = fork;
unless($pid) {
    # Make own process group to be able to kill HUP it later
    setpgrp;
    exec $ENV{SHELL}, "-c", ($bashfunc."@ARGV");
    die "exec: $!\n";
}
do {
    # Parent is not init (ppid=1), so sshd is alive
    # Exponential sleep up to 1 sec
    $s = $s < 1 ? 0.001 + $s * 1.03 : $s;
    select(undef, undef, undef, $s);
} until ($done || getppid == 1);
# Kill HUP the process group if job not done
kill(SIGHUP, -${pid}) unless $done;
wait;
exit ($?&127 ? 128+($?&127) : 1+$?>>8)
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.