Помогите с этой не -группой захвата с помощью grep?

Используя тот же подход, что и вы, используя временный файл, но делая его немного короче:

showqueue >/tmp/q.out; head -n 20 /tmp/q.out; echo '...'; tail -n 20 /tmp/q.out

Это не будет страдать от тех же проблем, которые обсуждались в другом ответе , но может отображать одни и те же строки дважды, если вывод был короче 40 строк.

0
11.06.2020, 17:16
3 ответа

Используемое вами регулярное выражение кажется слишком сложным, чтобы соответствовать только одному символу в середине, либо -, ., либо пробелу. Зачем вам [-.]?\s*?. Это читается как :Совпадение с -или .(, опционально (`? ))с последующим пробелом (ну, действительно (из man pcrepattern):Символы \s по умолчанию теперь HT (9 ), LF (10 ), VT (11 ), FF (12 ), CR (13 )и пробел (32 )). Ну, собственно, несколько пробелов в ленивом режиме (*? ).

На мой взгляд, все, что нужно, это [.-]просто, один символ, либо пробел, либо точка, либо тире. Это регулярное выражение:

(\d{5})[-. ](\d{6})

Лучше всего попробовать (единственный реальный способ выучить регулярные выражения )— зайти на regex101.com и попробовать. Здесь я создал пример этого поста подробно (в pcre, да ).

Вы видите, что в замену, о которой вы спрашиваете, я поставил эту замену:

(one:\1) (two:\2) (three:3)

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

Если вы хотите сделать первую (...)незахватывающей, тогда будет только одна группа захвата, и замена должна измениться на:

(one:1) (two:\1) (three:3)

Только один \1. В противном случае замена не удастся.

Если вы хотите заменить всю строку, сделайте так, чтобы она соответствовала всей строке от начала до конца:

^.*(?:\d{5})[-. ](\d{6}).*$

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

Теперь о grep. У Grep нет замен, есть что-то, что помогает, но не является хорошим эквивалентом:\K.

grep -Po '^.*\d{5}[-. ]\K\d{6}' file

Одна важная идея заключается в том, что -oпредназначен для выдачи всего, что соответствует регулярному выражению, да,все регулярное выражение, а не каждая совпадающая скобка.

Для работы с реальной заменой (или заменой(s///))вам нужен sed(, но он использует BRE, а не PCRE):

$ sed 's/^.*\([0-9]\{5\}\)[-. ]\([0-9]\{6\}\).*$/ \2 \1 /' file
 567890 01234 
 222111 01111 
 543210 09876

, который выполняет реальную замену и позволяет изменить порядок (или повторить ).

0
28.04.2021, 23:15

Если вы хотите grepвыделить только фрагменты строк, где последние 6 символов являются цифрами, просто скажите, что

grep -Po "\d{6}$" file

Добавьте внешний вид, если вы хотите быть уверенным в разделителе

grep -Po "(?<=[-. ])\d{6}$" file

Или, если количество цифр неопределенно

grep -Po "\d+$" file

Просто привяжите к концу строки и сопоставьте в обоих случаях.

Я считаю, что лучший план — это Обычно не иметь дело с теми частями, с которыми вам не нужно иметь дело, (хотя есть все добродетели в том, чтобы делать что-то трудным путем, чтобы учиться....так держать ;D ).

0
28.04.2021, 23:15

Захват не влияет на то, что grep считает совпавшими частями при использовании опции -oили --only-matching. Все не захватывающие -средства заключаются в том, что вы не собираетесь считать группу одной из доступных обратных ссылок (или замен в контекстах, где замена является опцией ).

Например:

$ printf 'aba\nabb\nabc\n' | grep -Po '(a)(b)'
ab
ab
ab
$ printf 'aba\nabb\nabc\n' | grep -Po '(a)(b)\1'
aba
$ printf 'aba\nabb\nabc\n' | grep -Po '(?:a)(b)\1'
abb

Вероятно, то, что вы ищете в этом контексте, является либо утверждением просмотра назад нулевой длины:

printf 'aba\nabb\nabc\n' | grep -Po '(?<=a)b'
b
b
b

или утверждение \K"держаться левой стороны"

$ printf 'aba\nabb\nabc\n' | grep -Po 'a\Kb'
b
b
b

(последний немного более гибкий, так как допускает сопоставление переменной длины ).

Так например

$ grep -Po '\d{5}[-.]?\s*\K\d{6}' file
567890
222111
543210
1
28.04.2021, 23:15

Теги

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