Sed регулярное выражение и отрицание подстроки - PullRequest
23 голосов
/ 29 января 2012

Каков правильный синтаксис для поиска подстроки (строка, которая предшествует и сопровождается определенными строками), которая не соответствует определенному шаблону?

Например, я хочувзять все подстроки, которые начинаются с BEGIN_, заканчиваются с _END, а подстрока между ними не равна FOO;и заменить всю подстроку на формат "( внутренняя подстрока )".Будет соответствовать следующее:

  • BEGIN_bar_END -> (bar)
  • BEGIN_buz_END -> (buz)
  • BEGIN_ihfd8f398IHFf9f39_END -> (ihfd8f398IHFf9f39)

Но BEGIN_FOO_END не будет соответствовать.

Я поиграл со следующим, но не могу найти правильный синтаксис:

sed -e 's/BEGIN_(^FOO)_END/($1)/g'
sed -e 's/BEGIN_([^FOO])_END/($1)/g'
sed -e 's/BEGIN_(?!FOO)_END/($1)/g'
sed -e 's/BEGIN_(!FOO)_END/($1)/g'
sed -e 's/BEGIN_(FOO)!_END/($1)/g'
sed -e 's/BEGIN_!(FOO)_END/($1)/g'

Ответы [ 4 ]

36 голосов
/ 29 января 2012

В sed, IIRC нет общего оператора отрицания, потому что компиляция регулярных выражений с отрицанием DFA занимает экспоненциальное время. Вы можете обойти это с

'/BEGIN_FOO_END/b; s/BEGIN_\(.*\)_END/(\1)/g'

где /BEGIN_FOO_END/b означает: если мы найдем BEGIN_FOO_END, то ответвление (переход) к концу сценария sed.

16 голосов
/ 27 января 2016

Эта тема может быть старой, но для полноты, как насчет оператора отрицания !:

Сделай все несчастными, стань ОЧЕНЬ СЧАСТЛИВЫМИ:

echo -e 'happy\nhappy\nunhappy\nhappy' | sed '/^happy/! s/.*/VERY HAPPY/'

Нашел это здесь: Как глобально заменить строки в строках, НЕ начиная с определенного шаблона

4 голосов
/ 29 января 2012

Это может работать для вас:

sed 'h;s/BEGIN_\(.*\)_END/(\1)/;/^(FOO)$/g' file

Это работает, только если в строке только одна строка.

Для нескольких строк в строке:

sed 's/BEGIN_\([^F][^_]*\|F[^O][^_]*\|FO[^O][^_]*\|FOO[^_]\+\)_END/\(\1\)/g' file

Или более легко понять:

sed 's/\(BEGIN_\)FOO\(_END\)/\1\n\2/g;s/BEGIN_\([^\n_]*\)_END/(\1\)/g;s/\n/FOO/g' file
2 голосов
/ 29 января 2012

Я не знаю красивого способа, но вы всегда можете сделать это:

$ cat file
BEGIN_FOO_END
BEGIN_FrOO_END
BEGIN_rFOO_END
$ sed '/BEGIN_FOO_END/ !{s/BEGIN_\([^_]*\)_END/(\1)/}' file 
BEGIN_FOO_END
(FrOO)
(rFOO)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...