Пожалуйста, не могли бы вы предоставить iptables -t filter -nvL
выходы на серверах B и C?
Я предполагаю, что канал autossh
работает на сервере C. Так ли это? Если да, то я предлагаю другой подход. На B вам нужно правило REDIRECT, потому что ядро не позволит непривилегированному пользователю открыть порт 80.
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 10000
iptables -t filter -A INPUT -p tcp --dport 10000 -j ACCEPT
(EDIT): На сервере B, GatewayPorts
должен быть включен в /etc/ssh/sshd_config
:
# /etc/ssh/sshd_config
GatewayPorts clientspecified
На сервере C, перенаправляйте соединения непосредственно на донгл, изменяя autossh
аргументы:
autossh -M 0 -N user@myserver.dyndns.com -R 10022:127.0.0.1:22 \
-R :10000:192.168.8.1:80
Единственная ошибка, которую я вижу в вашей установке, связана с правилом цепочки PREROUTING
на сервере C. В этом сценарии оно не будет оцениваться, поскольку влияет только на пакеты, входящие через сетевые интерфейсы. Соединения, создаваемые ssh
, генерируются локально, поэтому на них будут влиять правила в цепочке OUTPUT
.
Попробуйте:
awk '{x=x $0 ORS}; END{printf "%s", $0 ORS x}'
Определить переменную с помощью нашего ввода:
$ input="line 1
> line 2
> line 3"
Запускаем нашу команду:
$ echo "$input" | awk '{x=x $0 ORS}; END{printf "%s", $0 ORS x}'
line 3
line 1
line 2
line 3
В качестве альтернативы, конечно, мы могли бы использовать здесь -doc:
$ cat <<EOS | awk '{x=x $0 ORS}; END{printf "%s", $0 ORS x}'
line 1
line 2
line 3
EOS
line 3
line 1
line 2
line 3
x=x $0 ORS
Это добавляет каждую строку ввода к переменной x
.
В awk ORS
— это разделитель выходных записей . По умолчанию это символ новой строки.
END{printf "%s", $0 ORS x}
После того, как мы прочитали весь файл, выводится последняя строка $0
, за которой следует содержимое всего файла x
.
Так как это считывает весь ввод в память, это не подходит для больших (, например. гигабайт )входных данных.
cat <<EOS | sed -ne '1{h;d;}' -e 'H;${G;p;}'
line 1
line 2
line 3
EOS
Проблема с переводом этого на то, что использует tail
, заключается в том, что tail
нужно прочитать весь файл, чтобы найти его конец. Чтобы использовать это в своем конвейере, вам нужно
tail
. cat
. Хитрость заключается не в том, чтобы дублировать содержимое документа(tee
делает это ), а в том, чтобы вывод tail
происходил до вывода остальной части документа без использования промежуточного временного файла.
Использованиеsed
(или awk
, как это делает John1024,)избавляет от двойного разбора данных и проблемы упорядочения путем сохранения данных в памяти.
Решение, которое я предлагаю sed
состоит в том, чтобы
1{h;d;}
, сохранить первую строку в ячейке удержания, как -, и перейти к следующей строке. H
, добавляйте каждую другую строку в пространство для хранения со встроенным символом новой строки. ${G;p;}
, добавьте пробел к последней строке со встроенной новой строкой и распечатайте полученные данные.Это дословный перевод решения John1024 на sed
с той оговоркой, что стандарт POSIX гарантирует только то, что пространство хранения составляет не менее 8192 байт (8 КиБ; но он рекомендует , чтобы этот буфер динамически выделялся и расширялся по мере необходимости, что и GNU sed
и BSD sed
делают ).
Если вы позволите себе использовать именованный канал:
mkfifo mypipe
cat <<EOS | tee mypipe | cat <( tail -n 1 mypipe ) -
line 1
line 2
line 3
EOS
rm -f mypipe
Используется tee
для отправки данных вниз mypipe
и одновременно на cat
. Утилита cat
сначала прочитает вывод из tail
(, который считывается из mypipe
, который tee
записывает в ), а затем добавляет копию документа, поступающего непосредственно из tee
.
Однако в этом есть серьезная ошибка: если документ слишком велик,(превышает размер буфера канала ), запись tee
в mypipe
и cat
будет block, ожидая, пока (безымянный )канал опустеет. Он не будет опустошен, пока cat
не прочитает из него. cat
не будет читать из него, пока tail
не закончит. И tail
не закончится, пока tee
не закончится. Это классическая тупиковая ситуация.
Вариация
tee >( tail -n 1 >mypipe ) | cat mypipe -
имеет ту же проблему.
Если вас не волнует порядок. Тогда это сработает cat lines | tee >(tail -1)
. Как сказали другие. Вам нужно прочитать файл дважды или буферизовать весь файл, чтобы сделать это в том порядке, в котором вы просили.
Если stdin указывает на доступный для поиска файл (, как в случае bash (, но не во всех других документах оболочки ), которые реализованы с помощью временных файлов ), вы можете получить хвост, а затем искать назад, прежде чем читать полное содержание:
операторы seek доступны в оболочках zsh
или ksh93
или языках сценариев, таких как tcl/perl/python, но не в bash
. Но вы всегда можете вызвать эти более продвинутые интерпретаторы из bash
, если вам нужно использовать bash
.
ksh93 -c 'tail -n1; cat <#((0))' <<...
Или
zsh -c 'zmodload zsh/system; tail -n1; sysseek 0; cat' <<...
Теперь это не будет работать, когда стандартный ввод указывает на -недоступные для поиска файлы, такие как канал или сокет. Тогда единственным вариантом является чтение и сохранение (в памяти или во временном файле... )всего ввода.
Некоторые решения для сохранения в памяти уже были даны.
С временным файлом, с zsh
, вы можете сделать это с помощью:
seq 10 | zsh -c '{ cat =(sed \$w/dev/fd/3); } 3>&1'
Если в Linux с bash
или zsh
или любой оболочкой, которая использует временные файлы для здесь -документов, вы можете фактически использовать временный файл, созданный здесь -документом, для хранения вывода :
seq 10 | {
chmod u+w /dev/fd/3 # only needed in bash5+
cat > /dev/fd/3
tail -n1 /dev/fd/3
cat <&3
} 3<<EOF
EOF
Существует инструмент с именем pee
в наборе утилит командной строки -, обычно упакованных с именем «moreutils» (или иным образом загружаемых с его домашнего веб-сайта).
Если вы можете иметь его в своей системе, то эквивалент для вашего примера будет выглядеть так::
cat <<EOS | pee 'tail -1' cat
line 1
line 2
line 3
EOS
Порядок выполнения команд через pee
важен, поскольку они выполняются в заданной последовательности.
Попробуйте:
cat <<EOS # | what goes here now? Nothing!
line 3
line 1
line 2
line 3
EOS
Так как все это литеральные данные («здесь -есть документ» ), и разница между этим и желаемым результатом тривиальна, просто массируйте эти литеральные данные прямо здесь, чтобы они соответствовали выходным данным.
Теперь предположим, что line 3
приходит откуда-то и хранится в переменной с именемlastline
:
cat <<EOS # | what goes here now? Nothing!
$lastline
line 1
line 2
$lastline
EOS
В этом документе мы можем генерировать текст, подставляя переменные. Кроме того, мы можем вычислять текст, используя подстановку команд:
cat <<EOS
this is template text
here we have a hex conversion: $(printf "%x" 42)
EOS
Мы можем интерполировать несколько строк:
cat <<EOS
multi line
preamble
$(for x in 3 1 2 3; do echo line $x ; done)
epilog
EOS
В общем, избегайте обработки текста в шаблоне здесь документа; попробуйте сгенерировать его с помощью интерполированного кода.