Как вложить глобальные соответствия с sed?

[1122824] В онлайн-руководстве много информации для каждой команды; всегда стоит посмотреть на это, прежде чем сдаваться и задавать вопрос.

  • man echo[1123307] объясняет, какие последовательности выхода разрешены. Вот выдержка.

  • если -e действует, то распознаются следующие последовательности: \0NNN символ, чей ASCII-код является NNN (восьмеричный). \\ обратный слеш \a оповещение (BEL) обратное пространство \b \c не производить больше продукцию \f форма подачи \n новая строка возврат каретки \r горизонтальная вкладка \t вертикальная вкладка \v

  • Так что \x86 просто некорректен. он должен быть восьмеричным и заключить вашу строку в двойные кавычки, иначе она будет интерпретирована оболочкой.

  • Пример:

  • Редактирование 1

    1. Как напомнил мне Оуки, echo также является оболочкой сборки, так что информация находится на странице руководства по bash, [1123310]man bash[1123311]; вот соответствующий раздел. Но [1123312] используйте кавычки

    2. "[1123315] вокруг вашей строки, чтобы остановить оболочку, интерпретирующую обратные слэши.

    echo [-neE] [arg ...]. Выведите аргументы, разделенные пробелами, за которыми следует новая строка. Статус возврата всегда 0. Если указано -n, то новая колея подавляется. Если задан параметр -e, включена интерпретация следующих символов обратного слэша. Опция -E отключает интерпретацию этих экранирующих символов, даже в тех системах, где они находятся. интерпретируется по умолчанию. Опция оболочки xpg_echo может быть использована для динамического определения расширяет ли echo эти экранирующие символы по умолчанию или нет. echo не интерпретирует -- означает конец опций. Эхо интерпретирует следующие экранирующие последовательности: \a предупреждение (звонок) обратное пространство \b \c подавлять дальнейшее производство \e эвакуационный персонаж \f форма подачи \n новая строка возврат каретки \r горизонтальная вкладка \t вертикальная вкладка \v \\ обратный слеш \0nnn восьмиразрядный символ, значение которого равно восьмеричному значению nnn (от нуля до трех восьмеричных разрядов- свой) \xHH восьмиразрядный символ, значение которого является шестнадцатеричным значением HH (одна или две шестнадцатеричные цифры... свой)

    2
    31.10.2014, 17:49
    1 ответ

    Дело в том, что sed является жадным . Она будет кулдыкать как можно больше для каждого случая. Это может быть использовано в ваших интересах в лоббическом контексте замены s///g. Если вы \(group\) *нуль или больше совпадений строки, sed будет gсловесно кулдыкать первые в каждом случае. Таким образом, если вы можете надежно разграничить /соответствует этому/ |skip this|, вы можете сделать что-то вроде этого:

    sed 's/\([^<>]*<\)*\(match  *\)*\(remove  *\)*/\1/g
         s/.\{,45\}[^ ]*/&\
    /g;  s/\(\n\) */\1/g
    ' <<INPUT
    Never remove any match unless <the match \
    you want to remove is somehow delimited.> \
    And you can remove any match <per your match \
    delimiter as many times as your match occurs \
    within the match delimiters.>
    INPUT
    

    OUTPUT

    Never remove any match unless <the you want to
    is somehow delimited.> And you can remove any
    match <per your delimiter as many times as your
    occurs within the delimiters.>
    

    Вводится одна строка, потому что оболочка ускользает от новых строк в here-документе на обратных слешах. sed разделяет её на границы 45 char (give or take) и выводит на печать. Тем не менее, как вы видите, каждое появление либо совпадения с , либо удаляет за пределами границы <...>, в то время как все, что находится внутри этой границы, удаляется из вывода.

    Это функция жадности sed, поскольку она применима к совпаданию, происходящему *нуля или больше раз. Именно эта же жадность делает невозможной замену таким же образом, хотя это требует только дополнительного шага или двух, чтобы отрицать.

    Чтобы получить ясное представление о том, как это работает, мы можем выполнить замену - которая, кстати, вряд ли будет очень полезна при прямом применении, как я хочу показать:

    printf '%s %s\n' '<321Nu0-9mber123>' \
                     'String321strinG' \
                     '<321Nu0-9mber123>' \
                     'String321strinG' |
    sed 's/\(<[^<>]*>\)*[0-9]*/\1!/g'
    

    OUTPUT

    <321Nu0-9mber123>! !S!t!r!i!n!g!s!t!r!i!n!G!
    <321Nu0-9mber123>! !S!t!r!i!n!g!s!t!r!i!n!G!
    

    Таким образом, когда sed совпадает с линией на глобальном шаблоне, он пытается подобрать этот шаблон столько раз, сколько может, сохраняя при этом свою характерную жадность. Побочным эффектом жадности, когда указан образец для нуля или больше и он не совпадает с участком линии, является то, что он все еще совпадает с - он совпадает с нулевой строкой между байтами на участке линии, которому он не смог соответствовать.

    Выше видно, что строка <...> не подвержена влиянию, в то время как цифры, которые находились внутри строки String.... не только исчезли, но и что sed вставили взрыв для каждого символа. Это отражает соответствие sed для нуль-строки каждый раз. Именно по этой причине данный метод полезен для g словесного разграничения замены совпадения вместо того, чтобы делать его.

    И вот как это может работать:

    printf '%s\t%s\n' '<321Nu0-9mber123>' \
                    'String321strinG' \
                    '<321Nu0-9mber123>' \
                    'String321strinG' |
    sed 's/[0-9]/&\n/g;s/\(<[^<>]*>\)*\n*/\1/g;y/\n/0/'
    

    OUTPUT

    <302010Nu00-90mber102030>       String321strinG
    <302010Nu00-90mber102030>       String321strinG
    

    Это добавляет ноль к каждой цифре, которая встречается в пределах < и > - что довольно простой случай - но, на самом деле, вы можете использовать \newline символ таким образом, чтобы выполнить глобальную замену для любого совпадения . Основной принцип:

    1. Сделайте sed 's/match/&\n/g'
    2. Затем сделайте sed 's/\(match group\)*\n*/\1/g'
    3. Последнее сделайте sed 's/match\n/replace/g'

    Допускается, что эти примеры демонстрируют только примеры из плоского списка - < всегда предшествует >. Гнезда также нуждаются в рассмотрении. Они сложнее - иногда намного сложнее - но, что ж....

    sed 's/\([{}]\)\([^{}]*[{}]*\1\)*/\n<&>/g
    ' <<\INPUT
    {{{1!}{2!}{3!}}}outside!{{{4!}}{{5!}}}
    INPUT
    

    OUTPUT

    <{{{1!}{2!}{>3!
    <}}}>outside!
    <{{{4!}}{{>5!
    <}}}>
    

    Он сериализует группы на новых линиях. Он работает путем чередования разделителя, которому он соответствует на группу матчей, при одновременной укладке как можно большего количества одного и того же доброго разделителя подряд (как минимум дважды) и в качестве побочного эффекта приводит сравнение открывающихся и закрывающихся окон. При этом, для простоты, все остальное будет предполагать, что любой читатель будет использовать аналогичное средство для подготовки входных данных, и гнезда не являются проблемой.

    По сути, оперативная идея ко всему этому - это совпадение по приоритетности. Первый пример работал путем попытки сопоставить любую группу неделящихся символов непосредственно перед открытым разделителем, прежде чем пытаться сопоставить строки удаления. Вполне логично, что если первая группа совпадает, то когда подстановка дополняет всю совпадающую группу, она может быть заменена только на саму себя - и это может затруднить замену. Удаление более простое, потому что когда вы совпадаете с ними, вы просто исключаете их из подстановок, и все в порядке. Также в

    sedsed больше, чем другие, оценивает некоторые типы шаблонов. Важно понимать, что при этом любой указанный паттерн определенно всегда будет иметь больший вес, чем случай *нуль или больше . Поэтому когда вы используете их для глобальных шаблонов, используйте только * или не используйте их вообще - иначе вы можете пропустить ни одной группы вообще.

    И вот как вы это делаете с sed.

    2
    27.01.2020, 22:13

    Теги

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