Я не думаю, що ти можеш це обійти.
З -tt
, sshd
породжує псевдотермінал і робить підлеглий частиною stdin, stdout і stderr оболонки, яка виконує віддалену команду.
sshd
читає те, що надходить з його (одиночного) fd в головну частину псевдотерміналу і надсилає це (через один єдиний канал) ssh
клієнту. Не існує другого каналу для stderr, як і без нього -t
.
Крім того, зауважте, що дисципліна термінальної лінії псевдотерміналу може (і буде за замовчуванням) змінювати вихід. Наприклад, LF буде перетворений в CRLF там, а не на локальному терміналі, тому ви можете відключити вихідну післяобробну обробку.
$ 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
На вхідній стороні відбудеться набагато більше речей (на зразок ^C
символу, який спричинить SIGINT, але також і інші сигнали, відлуння та всі керування, що беруть участь у редакторі ліній канонічного режиму ).
Ви, можливо, можете перенаправити stderr на FIFO і отримати його за допомогою секунди ssh
:
ssh -tt host 'mkfifo fifo && cmd 2> fifo' &
ssh host 'cat fifo' >&2
Але найкраще було б уникати використання ІМО -t
. Це справді призначене лише для інтерактивного використання з реального терміналу.
Замість того, щоб покладатися на передачу ^ C, щоб віддалений кінець з'єднання був закритим, ви можете використовувати обгортку, яка робить a poll()
для виявлення вбитого ssh
або закритого зв'язку.
Можливо щось на зразок (спрощено, ви хочете додати перевірку помилок):
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)
Вище може здатися дурним, але ідея полягає в тому, щоб чекати , поки подія похмілля HUP (на кінець читання труби на стандартний висновок повинен бути закритий). POLLHUP як запитувана маска ігнорується. POLLHUP має значення лише як подія, що повернулася (щоб сказати, що кінець написання закрито).
Ми маємо дати ненульове значення для маски події. Якщо ми використовуємо 0
, perl
навіть не дзвонимо poll
. Тому тут ми використовуємо POLLIN.
У Linux, що б ви не запитали, якщо труба зламана, опитування () повертає POLLERR.
У Solaris та FreeBSD, де труби двонаправлені, коли кінець зчитування труби (який також є записуючим кінцем) закритий, він повертається за допомогою POLLHUP (та POLLIN на FreeBSD, де потрібно запитувати POLLIN або ще $p->poll()
ні. повернення).
Я не можу сказати, наскільки він портативний за межами цих трьох операційних систем.
parallel --tag -j1 'ssh -tt localhost perl/catch_wrap perl/catch_all_signals & sleep 1; killall -{} ssh' ::: {1..31}
але видаліть '-tt' і тоді він не працює.