Я столкнулся с этой проблемой на сервере с более ранней версией OpenSSH.Я управляю сервером и решил проблему, создав два CNAME в моей именованной конфигурации:
realhost.myexample.com. IN A XXX.XXX.XXX.XXX
realhost2.myexample.com. IN CNAME realhost.myexample.com.
realhost3.myexample.com. IN CNAME realhost.myexample.com.
Затем в моей локальной конфигурации клиента ssh:
ControlMaster auto
ControlPath ~/.ssh/%r_%p_%h
host realhost
hostname realhost.myexample.com
host realhost2
hostname realhost2.myexample.com
host realhost3
hostname realhost3.myexample.com
Оператор ControlPath таков, что имена управляющих сокетов не наступают друг на друга .
Вот и все, но чтобы упростить управление, я написал сценарий оболочки для 'ssh' на стороне клиента. Он понимает, что существуют «группы» хостов (в этом случае realhost, realhost1, realhost2 составляют одну группу). При выдаче sshwrapper realhost, если нет открытых каналов, открываются все три и начинается один сеанс. При следующем запуске он подсчитывает количество открытых подключений на канал и открывает новый сеанс в канале с наименьшим количеством подключений.
С одним реальным и двумя «фальшивыми» хостами я могу подключиться 30 раз, прежде чем получу ошибку. Вход в систему происходит очень быстро, за исключением того, что начальное время занимает секунду или две, так как в это время открываются все три канала управления.
Если вы знаете, что ввод не содержит символов <
или >
, вы можете сделать:
sed '
# replace opening quote with <
s|\[quote=[^]]*\]|<|g
# and closing quotes with >
s|\[/quote\]|>|g
:1
# work our way from the inner quotes
s|<[^<>]*>||g
t1'
Если он может содержать символы <
или >
, вы можете избежать их, используя схему, подобную:
sed '
# escape < and > (and the escaping character _ itself)
s/_/_u/g; s/</_l/g; s/>/_r/g
<code-above>
# undo escaping after the work has been done
s/_r/>/g; s/_l/</g; s/_u/_/g'
С perl
с использованием рекурсивных регулярных выражений:
perl -pe 's@(\[quote=[^\]]*\](?:(?1)|.)*?\[/quote\])@@g'
Или даже, как вы упомянули:
perl -pe 's@(\[quote=.*?\](?:(?1)|.)*?\[/quote\])@@g'
С помощью perl
вы можете обрабатывать многострочный ввод, добавляя опцию -0777
. С sed
вам нужно будет добавить к коду префикс :
:0
$!{
N;b0
}
Чтобы загрузить весь ввод в пространство шаблонов.
Небольшой скрипт, который увеличивает переменную счетчика для каждой начальной -кавычки и уменьшает ее для каждой конечной -кавычки. Если переменная-счетчик больше 0
, то текстовые фрагменты пропускаются.
#!/bin/bash
# disable pathname expansion
set -f
cnt=0
for i in $(<$1); do
# start quote
if [ "${i##[quote=}" != "$i" ] && [ "${i: -1}" = "]" ]; then
((++cnt))
elif [ "$i" = "[/quote]" ]; then
((--cnt))
elif [ $cnt -eq 0 ]; then
echo -n "$i "
fi
done
echo
Выход:
$ cat q1
text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3
$./parse.sh q1
text part 1 text part 2 text part 3
$ cat q2
text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [foo] [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3
$./parse.sh q2
text part 1 text part 2 text part 3
Я проверил это, и оно у меня сработало. Возможно, вы захотите выбрать другой временный шаблон вместо foobar
. Без него sed
удалил все между тегами, оставив толькоtext part 1 text part 3
sed -e 's/\/quote\]/foobar\]/3' -e 's/\[.*\/quote\]//' -e 's/\[.*foobar]//' testfile
вместо этого, если testfile
вы можете просто передать это с помощьюcat
Вы можете сделать это с помощью POSIX sed
, как описано здесь. Обратите внимание, что это решение применимо к обоим типам показанных вами входных данных. Ограничения: ввод не является многострочным, так как мы используем новые строки в качестве маркеров для эффекта. требуется трансформация.
$ sed -e '
:top
/\[\/quote]/!b
s//\
&/
s/\[quote=/\
\
&/
:loop
s/\(\n\n\)\(\[quote=.*\)\(\[quote=.*\n\)/\2\1\3/
tloop
s/\n\n.*\n\[\/quote]//
btop
' input.txt