ответ elbarna - это способ настройки параметров конфигурации "изначально", поддерживаемых libvirt (и, следовательно, его доменом XML). Для аргументов командной строки qemu (и других), не поддерживаемых libvirt, необходимо включить объявление пространства имен XML qemu в корневой элемент 'domain':
В вашем случае вы можете просто инвертировать закрывающий символ следующим образом:
echo 'ssABteAstACABnnACss' | sed 's/AB[^C]*AC/XXX/'
Регулярные выражения Sed соответствуют самому длинному совпадению. У седла нет эквивалента нежадному.
Мы хотим сопоставить
AB
, AC
, AC
К сожалению, sed
не может выполнить №2 -
, по крайней мере, не для многосимвольных регулярных выражений. Конечно,
для односимвольного регулярного выражения, такого как @
(или даже [123]
),
мы можем сделать [^ @] *
или [^ 123] *
.
Таким образом, мы можем обойти ограничения sed
, заменив все вхождения AC
на @
, а затем выполнив поиск
AB
, @
, @
, например:
sed 's/AC/@/g; s/AB[^@]*@/XXX/; s/@/AC/g'
Последняя часть заменяет несопоставленные экземпляры @
обратно на AC
.
Но это безрассудный подход
, потому что ввод уже мог содержать @
символов.
Таким образом, сопоставив их, мы могли получить ложные срабатывания. Однако
, поскольку ни в одной переменной оболочки никогда не будет символа NUL ( \ x00
), NUL, вероятно, будет хорошим символом для использования в описанном выше обходном пути вместо @
:
$ echo 'ssABteAstACABnnACss' | sed 's/AC/\x00/g; s/AB[^\x00]*\x00/XXX/; s/\x00/AC/g'
ssXXXABnnACss
Для использования NUL требуется GNU sed. (Чтобы убедиться, что функции GNU включены, пользователь не должен устанавливать переменную оболочки POSIXLY_CORRECT.)
Если вы используете sed с флагом GNU -z
для обработки ввода, разделенного NUL, например вывод find ... -print0
, тогда NUL не будет в пространстве шаблонов, и NUL - хороший выбор для замены здесь.
Хотя NUL не может быть в переменной bash, его можно включить в команду printf
. Если ваша входная строка может содержать любой символ, включая NUL, см. ответ Стефана Шазеласа , в котором добавлен умный метод экранирования.
Некоторые реализации sed
поддерживают это. ssed
имеет режим PCRE:
ssed -R 's/AB.*?AC/XXX/'
AT&T ast sed поддерживает оператор *?
как нежадную версию *
в своем ] расширенный (с -E
) и расширенный (с -A
регулярными выражениями).
sed -E 's/AB.*?AC/XXX/'
sed -A 's/AB.*?AC/XXX/'
В этой реализации и в режимах -E
/ -A
, в более общем смысле, регулярные выражения, подобные Perl, могут использоваться внутри (? P: Perl-like regexp здесь )
, хотя, как показано выше, это не обязательно для оператора *?
.
Его расширенные регулярные выражения также имеют операторы соединения и отрицания:
sed -A 's/AB(.*&(.*AC.*)!)AC/XXX/'
В переносном смысле вы можете использовать этот метод: замените конечную строку (здесь AC
) одним символом, который не соответствует 'не встречается ни в начале, ни в конце строки (например, :
здесь), поэтому вы можете сделать s / AB [^:] *: //
, и в случае, если этот символ может появиться во вводе используйте механизм экранирования, который не конфликтует с начальной и конечной строками.
Пример:
sed 's/_/_u/g; # use _ as the escape character, escape it
s/:/_c/g; # escape our replacement character
s/AC/:/g; # replace the end string
s/AB[^:]*:/XXX/; # actual replacement
s/:/AC/g; # restore the remaining end strings
s/_c/:/g; # revert escaping
s/_u/_/g'
В GNU sed
подход заключается в использовании новой строки в качестве символа замены. Поскольку sed
обрабатывает одну строку за раз, новая строка никогда не появляется в пространстве шаблонов, поэтому можно сделать следующее:
sed 's/AC/\n/g;s/AB[^\n]*\n/XXX/;s/\n/AC/g'
Это обычно не работает с другими реализациями sed
, потому что они не не поддерживает [^ \ n]
. С GNU sed
вы должны убедиться, что совместимость с POSIX не включена (как с переменной среды POSIXLY_CORRECT).
Нет, у sed regexes нет не жадного сопоставления.
Вы можете найти весь текст до первого вхождения AC
, используя "anything not containing AC
", за которым следует AC
, что делает то же самое, что и .*?AC
в Perl. Дело в том, что "все, что не содержит AC
" не может быть легко выражено в виде регулярного выражения: всегда есть регулярное выражение, которое распознает отрицание регулярного выражения, но регекс отрицания быстро усложняется. А в переносимом sed это вообще невозможно, поскольку регекс отрицания требует группировки - чередования, которое присутствует в расширенных регулярных выражениях (например, в awk), но не в переносимых базовых регулярных выражениях. Некоторые версии sed, такие как GNU sed, действительно имеют расширения BRE, которые делают его способным выражать все возможные регулярные выражения.
sed 's/AB\([^A]*\|A[^C]\)*A*AC/XXX/'
Из-за сложности отрицания регулярного выражения это не очень хорошо обобщается. Вместо этого можно временно преобразовать строку. В некоторых реализациях sed в качестве маркера можно использовать новые строки, поскольку они не могут появляться в строке ввода (а если вам нужно несколько маркеров, используйте новую строку, за которой следует изменяющийся символ).
sed -e 's/AC/\
&/g' -e 's/AB[^\
]*\nAC/XXX/' -e 's/\n//g'
Однако имейте в виду, что backslash-newline не работает в наборе символов некоторых версий sed. В частности, это не работает в GNU sed, который является реализацией sed в Linux без расширения; в GNU sed вы можете использовать \n
вместо этого:
sed -e 's/AC/\
&/g' -e 's/AB[^\n]*\nAC/XXX/' -e 's/\n//g'
В этом конкретном случае достаточно заменить первый AC
на новую строку. Подход, который я представил выше, является более общим.
Более мощный подход в sed - сохранить строку в пространство hold, удалить все, кроме первой "интересной" части строки, поменять местами пространство hold и пространство шаблона или добавить пространство шаблона к пространству hold и повторить. Однако, если вы начинаете делать настолько сложные вещи, вам стоит задуматься о переходе на awk. В awk также нет жадного сопоставления, но вы можете разделить строку и сохранить части в переменных.
Решение очень простое. .*
является жадным, но не совсем жадным. Рассмотрим сопоставление ssABteAstACABnnACss
с регулярным выражением AB.*AC
. AC
, следующее за .*
, должно иметь совпадение. Проблема в том, что поскольку .*
жадный, последующий AC
будет соответствовать последнему AC
, а не первому..*
поглощает первый AC
, в то время как литерал AC
в регулярном выражении совпадает с последним в ssABteAstACABnn AC ss. Чтобы этого не произошло, просто замените первое AC
чем-нибудь нелепым , чтобы отличить его от второго и от всего остального.
echo ssABteAstACABnnACss | sed 's/AC/-foobar-/; s/AB.*-foobar-/XXX/'
ssXXXABnnACss
Жадный .*
теперь остановится у подножия -foobar-
в ssABteAst-foobar-ABnnACss
, потому что нет другого -foobar-
, кроме этого -foobar-
, и регулярное выражение-foobar-
ДОЛЖНО иметь совпадение. Предыдущая проблема заключалась в том, что регулярное выражение AC
имело два совпадения, но поскольку .*
было жадным, было выбрано последнее совпадение для AC
. Однако с -foobar-
возможно только одно совпадение, и это совпадение доказывает, что .*
не является абсолютно жадным. Автобусная остановка для .*
происходит там, где только одно совпадение остается для остальной части регулярного выражения, следующего за .*
.
Обратите внимание, что это решение не будет работать, если AC
появится перед первым AB
, потому что неправильный AC
будет заменен на -foobar-
. Например, после первой замены sed
ACssABteAstACABnnACss
становится -foobar-ssABteAstACABnnACss
; следовательно, совпадение с AB.*-foobar-
не может быть найдено. Однако, если последовательность всегда...AB...AC...AB...AC..., то это решение будет успешным.
Один из вариантов — изменить строку таким образом, чтобы вы хотели жадное совпадение
echo "ssABtCeCAstACABnnACss" | rev | sed -E "s/(.*)CA.*BA(.*)/\1CA+-+-+-+-BA\2/" | rev
Используйте rev
, чтобы инвертировать строку, инвертируйте критерии соответствия, используйте sed
обычным способом, а затем инвертируйте результат....
ssAB-+-+-+-+ACABnnACss