Настройка OpenVPN клиента для использования топологии подсети приводит к тому, что «ожидается префикс inet, а не 10,66,10 .6/-1»

Я не думаю, что вы сможете обойти это.

С -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

Но лучше всего, IMO, вообще не использовать -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) может показаться глупой, но идея заключается в том, чтобы ждать события зависания (закрытия читающего конца трубы на stdout). POLLHUP как запрошенная маска игнорируется. POLLHUP имеет смысл только как событие возврата (чтобы сообщить, что конец записи был закрыт).

Мы должны дать ненулевое значение для маски события. Если мы используем 0, perl даже не вызовет poll. Поэтому здесь мы используем POLLIN.

В Linux, что бы вы ни запросили, если труба становится разорванной, poll() возвращает POLLERR.

На Solaris и FreeBSD, где трубы двунаправленные, когда конец трубы для чтения (который там же является и концом для записи) закрывается, возвращается POLLHUP (и POLLIN на FreeBSD, где вы должны запросить POLLIN, иначе $p->poll() не возвращается).

Я не могу сказать, насколько она переносима за пределами этих трех операционных систем.

1
29.12.2018, 17:54
2 ответа

Так как bashв любом случае не может хранить NUL-байты в своих переменных, вы всегда можете сделать:

IFS= read -rd '' var < file

в котором будет храниться содержимое файла до первого нулевого байта или конца файла, если в файле нет нулевых байтов (текстовые файлы по определению (по определению POSIX по крайней мере )не содержат байты NUL ).

Другим вариантом является сохранение содержимого файла в виде массива его строк (, включая разделитель строк, если он есть):

readarray array < file

Затем вы можете присоединиться к ним с помощью:

IFS=; var="${array[*]}"

Если вход содержит байты NUL, все, что находится после первого вхождения в каждой строке, будет потеряно.

В синтаксисе POSIX sh вы можете сделать:

var=$(cat < file; echo.); var=${var%.}

Мы добавляем ., который затем удаляем, чтобы обойти тот факт, что подстановка команд удаляет все завершающие символы новой строки.

Если файл содержит байты NUL, поведение будет различаться в зависимости от реализации.zsh— единственная оболочка, которая их сохранит. (это также единственная оболочка, которая может хранить байты NUL в своих переменных ). bashи несколько других оболочек просто удаляют их, в то время как некоторые другие задыхаются от них и отбрасывают все после первого появления NUL.

Вы также можете хранить содержимое файла в какой-либо закодированной форме, например:

var=$(uuencode -m - < file)

И получить обратно с:

printf '%s\n' "$var" | uudecode

Или с NUL, закодированными как \0000, чтобы иметь возможность использовать его в аргументах для printf %bв bash(, предполагая, что вы не используете локали с кодировкой BIG5, GB18030, GBK, BIG5 -HKCSC):

var=; while true; do
  if IFS= read -rd '' rec; then
    var+=${rec//\\/\\\\}\\0000
  else
    var+=${rec//\\/\\\\}
    break
  fi
done < file

А потом:

printf %b "$var"

, чтобы получить его обратно.

4
27.01.2020, 23:11

Ответ, как правило, "нет", просто потому, что -по общему правилу -в файле нет фактического символа, который окончательно отмечает конец файла.

Возможно, вам стоит попробовать другой подход, например один из предложенных здесь:https://stackoverflow.com/questions/10984432/how-to-read-the-file-content-into-a-variable-in-one-go. Использование:

IFS="" contents=$(<file)

особенно элегантен; это заставляет Bash считывать содержимое fileв переменную contents, за исключением байтов NULL -, которые переменные Bash -не могут хранить (из-за внутреннего использования стиля C -., NULL -строки с завершением байта ). IFS=""устанавливает внутренний разделитель полей пустым, чтобы отключить разделение слов (и, следовательно, избежать удаления новых строк ).

Примечание :Так как (из-за отсутствия очков репутации )я не могу комментировать ответ, предполагающий использование readс опцией -N, отмечу здесь, что этот ответ -по определению -не гарантирует работу в том виде, в каком он есть, поскольку размер файла заранее неизвестен.

3
27.01.2020, 23:11

Теги

Похожие вопросы