Я не думаю, что вы можете обойти это.
С -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, чтобы позволить удаленному концу соединение закрыться, вы могли бы использовать оболочку, которая делает 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
. Так что здесь мы используем Поллин.
В Linux, что бы вы ни запросили, если канал разорван, poll () возвращает 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' и тогда это не будет работать.