PCRE-regex Используйте grep для исключения группы захвата

Сортировать по для некоторых ключевых столбцов используйте следующее:

awk '!duplicate[$1,$2,$3]++' file_1 file_2

здесь рассматривайте первый, второй и третий столбцы в качестве первичного ключа.

6
28.11.2016, 13:48
1 ответ

grep Имя идет после g / re / p ed команда. Его основная цель - напечатать строки, соответствующие регулярному выражению. Редактировать содержимое этих строк не его роль. Для этого у вас есть sed (редактор потока) или awk .

Теперь в некоторых реализациях grep , начиная с GNU grep , добавлен параметр -o для печати совпадающей части каждой строки (что соответствует regexp, а не его группы захвата). У вас есть реализация grep , подобная GNU (с -P ) или pcregrep , которые поддерживают PCRE для своих регулярных выражений.

pcregrep фактически добавил параметр -o для печати содержимого группы захвата.Итак, вы можете сделать:

pcregrep -o1 -o2 --om-separator=' ' '.zoo.(\d+).*:\s+(.*)'

Но здесь очевидное стандартное решение - использовать sed :

sed -n 's/^.*\.zoo\.\([0-9]\{1,\}\).*:[[:space:]]\{1,\}/\1 /p'

Или, если вам нужны регулярные выражения Perl, используйте perl:

perl -lne 'print "$1 $2" if /\.zoo\.(\d+).*:\s+(.*)/'

С GNU grep , если вы не против, чтобы совпадения отображались в разных строках, вы можете сделать:

$ grep -Po '\.zoo\.\K\d+|:\s+\K.*' < file
2
0.45654343

Обратите внимание, что хотя \ K сбрасывает начало совпадающей части, это не означает, что вы можете получить прочь с перекрытием двух частей чередования.

 grep -Po '.zoo. (\ K \ d + |. : \ K. )' 

не будет работать, как и echo foobar | grep -Po 'foo | foob' не будет работать (при печати как foo , так и foob ). foo | foob сначала соответствует foo , а затем grep ищет возможные другие совпадения во входных данных после foo , поэтому, начиная с b из бара , поэтому больше ничего не могу найти.

Выше с grep -Po '\ .zoo \. \ K \ d + |: \ s + \ K. *' , мы ищем только : <пробелы> <что-нибудь> во второй части чередования. Это соответствует части, которая находится после .zoo. , но это также означает, что он найдет эти : где угодно во входных данных, а не только когда они следуют за .zoo. <цифры> .

Однако есть способ обойти это, используя другой специальный оператор PCRE: \ G . \ G соответствует началу темы.Для одного совпадения это эквивалентно ^ , но с несколькими совпадениями (подумайте о sed / perl флаге g в s /.../.../ g ) как с -o , где grep пытается найти все совпадения в строке, которая также совпадает после конец предыдущего матча. Итак, если вы сделаете это:

grep -Po '\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'

Где (?! ^) - оператор отрицательного просмотра вперед, что означает не в начале строки , что \ G будет соответствовать только после предыдущего успешного (непустого) совпадения, поэтому . *: \ S + \ K. * будет соответствовать, только если он следует за предыдущим успешным совпадением, и это может быть только .foo. один, поскольку другая часть чередования совпадает до конца строки.

На входе вроде:

.zoo.1.zoo.2 tar: blah

Что бы вывести:

1
2
blah

Хотя. Если вы этого не хотите, вы бы также хотели, чтобы первая часть чередования совпадала только с началом строки. Что-то вроде

grep -Po '^.*?\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'

Это все еще выводит 2 на входе типа .zoo.2 без символа двоеточия или .zoo.2 blah: . Вы можете обойти это с помощью оператора упреждающего просмотра в первой части чередования и найти хотя бы один непробел после : (а также с помощью $ чтобы избежать проблем с не-символами)

grep -Po '^.*?\.zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'

Вам, вероятно, понадобится несколько страниц комментариев, чтобы объяснить это регулярное выражение, поэтому я бы все равно выбрал прямые sed / perl решения ...

12
27.01.2020, 20:25

Теги

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