Использование регулярных выражений (регулярных выражений) в sed

У Red Hat есть глобальный файл ресурсов в /etc/vimrc.

Можно проверить с помощью:

$ strace -eopen -o log vim test
$ grep vimrc log
open("/etc/vimrc", O_RDONLY)            = 3
open("/root/.vimrc", O_RDONLY)          = -1 ENOENT (No such file or directory)
open("/root/_vimrc", O_RDONLY)          = -1 ENOENT (No such file or directory)
2
29.05.2020, 00:35
1 ответ

Вам нужно автоматизированное решение, слишком много всего, чтобы цитировать и отслеживать.

Двухэтапное решение (не на 100 % идеально (могут быть патологические угловые случаи ))это:

  1. Получить строку дословно в переменной.

    • Почему? Потому что содержимое переменной (в кавычках )("$var")никогда не изменяется (снова )оболочкой.
    • Как? Используйте строку в кавычках здесь -.

    Шаги:

    • Напишите:IFS= read -r var <<\ENDв командной строке
    • скопируйте и вставьте точно такую ​​же строку, которую вы хотите обработать, нажмите Enter
    • напишите ENDи снова нажмите Enter.

    Затем переменная var будет содержать точно такую ​​же строку, которую вы скопировали в командной строке, без изменений, без удаления кавычек, без ничего, просто строка.

    Вы должны увидеть:

    $ IFS= read -r var <<\END
    > $GLOBALS['timechecks']=addTimeCheck_sparky($GLOBALS['timechecks'], number_format(microtime(true),6,'.',''), __LINE__, basename(__FILE__));
    > END
    

    Готово, да, вот и вся сложная часть, скопируйте и вставьте.
    Вы можете повторить строку:

    $ echo "$var"
    $GLOBALS['timechecks']=addTimeCheck_sparky($GLOBALS['timechecks'], number_format(microtime(true),6,'.',''), __LINE__, basename(__FILE__));
    

    Лучше использовать printf '%s\n' "$var" to avoid issues with some values ofvar that may start with a-`, но в этом примере эхо работает нормально.

С этого момента вам больше не нужно будет ничего печатать/вводить/"выполнять вручную".
Вам просто нужно скопировать -и вставить команду ниже.

  1. Используйте значение var, чтобы сгенерировать точное регулярное выражение, используемое в sed, чтобы точно соответствовать ему. Тип регулярного выражения, который принимает sed, называется BRE (Basic Regular Expression )согласно POSIX .
    В BRE есть несколько специальных символов \.[**^$.
    Если все эти символы заключены в кавычки, регулярное выражение на самом деле является дословной строкой оригинала. Это легко сделать(\.*^$[):

    $ echo "$var" | sed 's#\([\.*^$[]\)#\\\1#g'
    $GLOBALS\['timechecks']=addTimeCheck_sparky($GLOBALS\['timechecks'], number_format(microtime(true),6,'.',''), __LINE__, basename(__FILE__));
    

    Процитированное (экранировано )любой обратной косой чертой (\), открывающей ([), точкой (.), звездочкой (*), циркумфлексом(^)и знаком доллара -($).Это сломало бы любую возможную конструкцию регулярного выражения в varи преобразовало бы их все в простую строку. Он разбивает любое "выражение в квадратных скобках" ([), любой "любой символ" (.), любое повторение (*), любую привязку(^$)и любую обратную косую черту(\).
    Обратите внимание, что любые (, ), {или }не требуют экранирования. Если не сбежали, то остаются, а потому не похожи (на особые\(). Если экранировано (\(), они становятся \\(, также теряя какое-либо особое значение.

    Могут быть патологические угловые случаи, которые я не могу увидеть прямо сейчас, но в 99,2% случаев простого преобразования должно быть достаточно.

Затем вы можете захватить измененную строку и использовать ее в sed:

$ reg=$(echo "$var" | sed 's#\([\.*^$[]\)#\\\1#g')

$ echo "$var" | sed 's#'"$reg"'# ===any string=== #'
 ===any string=== 

Если преобразование было правильным, команда sed должна захватить всю исходную строку и заменить ее строкой с правой стороны.

Конечно, если вы хотите, чтобы совпадала более короткая часть строки, просто начните с той части, с которой вы хотите совпасть.

Дополнительно Если вы хотите увидеть, какую строку вы должны были написать, чтобы получить правильную строку внутри переменной (, которая требует дополнительного уровня цитирования ), вы можете использовать (bash 4.3+):

$ myvar=$(echo "${var}" | sed 's#\([\.*^$[]\)#\\\1#g')
$ echo "${myvar@Q}"
'\$GLOBALS\['\''timechecks'\'']=addTimeCheck_sparky(\$GLOBALS\['\''timechecks'\''], number_format(microtime(true),6,'\''\.'\'','\'''\''), __LINE__, basename(__FILE__));'

Если написать что-то вроде:

$ myvar='\$GLOBALS\['\''timechecks'\'']=addTimeCheck_sparky(\$GLOBALS\['\''timechecks'\''], number_format(microtime(true),6,'\''\.'\'','\'''\''), __LINE__, basename(__FILE__));'

Один уровень цитирования удаляется, и вы получаете внутри myvarнеобходимую строку для работы.

Вы можете сравнить свою первоначальную попытку и увидеть, что пошло не так.:

Bad:     \$GLOBALS\['\''timechecks'\''\]=addTimeCheck_sparky[(]$GLOBALS\['\''timechecks'\''\][,][ ]number_format[(]microtime[(]true[)][,]6[,]'\''\.'\''[,]'\'''\''[)][,][ ]__LINE__[],[ ]basename[(]__FILE__[)][)][;]
Good:   '\$GLOBALS\['\''timechecks'\'']=addTimeCheck_sparky(\$GLOBALS\['\''timechecks'\''], number_format(microtime(true),6,'\''\.'\'','\'''\''), __LINE__, basename(__FILE__));'

Надеюсь, что это даст вам общую схему защиты от дурака, чтобы цитировать что-нибудь.

Примечание.:Я создал описанную выше процедуру для базовых регулярных выражений BRE для sed. Это все регулярные выражения, которые sed понимает (по умолчанию ). Если sed вызывается как sed -E, то используются расширенные регулярные выражения (ERE). Есть некоторые изменения для ERE. Список специальных символов увеличивается до :.[\()*+?{|^$, поэтомуэкранирование должно быть (нет, мы не можем использовать здесь расширенные регулярные выражения, так как они не позволяют использовать обратные -ссылки):

sed 's@\([\.()*+?{|^$[]\)@\\\1@g'

Вы можете увидеть, как это работает, на этой странице, которую я подготовил

Я не имею в виду PCRE (Perl )JavaScript, PHP или любые другие разновидности регулярных выражений, поскольку sed не может их использовать , точка, бесполезно.

Связанные:

BRE --Основные регулярные выражения POSIX

3
18.03.2021, 23:32

Теги

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