Як витягти текст із рядка за допомогою sed?


95

Мій приклад рядка такий:

This is 02G05 a test string 20-Jul-2012

Тепер із наведеного рядка я хочу витягти 02G05. Для цього я спробував наступний регулярний вираз із sed

$ echo "This is 02G05 a test string 20-Jul-2012" | sed -n '/\d+G\d+/p'

Але вищевказана команда нічого не друкує, і я вважаю, що вона не може зрівняти нічого з шаблоном, який я надав sed.

Отже, моє питання полягає в тому, що я тут роблю не так і як це виправити.

Коли я пробую наведені вище рядки та шаблони за допомогою python, я отримую свій результат

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>

6
Python точно не є sed. Їх смакові рецепти досить різні.
— тричі

Відповіді:


91

Можливо \d, ваш шаблон не підтримує шаблон sed. Спробуйте [0-9]або [[:digit:]]замість цього.

Щоб надрукувати лише фактичну відповідність (а не весь відповідний рядок), використовуйте заміну.

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'

6
Дякую, це спрацювало нормально. Але у мене виникає запитання, чому .*це потрібно з вашим регулярним виразом, тому що при спробі sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p'він просто друкує весь рядок.
— RanRag

7
Ось чому, чи не так? Замініть усе, що надходить до і після матчу, норшинг, а потім надрукуйте весь рядок.
— триплі

1
@tripleee Це лише 2G05не друкує 02G05. Працює вираз's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
— Kshitiz Sharma

1
Це жорстко кодує його рівно до двох цифр. Щось подібне sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'було б більш загальним. (Я припускаю, що ваша sedпідтримка не буде \?нульовим або одним випадком.)
— tripleee

Дивіться також stackoverflow.com/a/48898886/874188 про те , як замінити різні інші загальні Perl вислизає , як \w, \sі т.д.
— tripleee

99

Як щодо використання grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'

3
+1 Це простіше, і воно також буде правильно обробляти випадки декількох збігів на одному рядку. Для sedцього випадку можна розробити складний сценарій, але навіщо турбуватися?
— триплеє

egrepвикористовує розширений регулярний вираз sedі grepвикористовує стандартний регулярний вираз, egrepабо grep -eабо sed -Eвикористовує розширений регулярний вираз, а код python у питанні використовує PCRE, (загальний регулярний вираз perl) GNU grep може використовувати PCRE з -Pопцією.
— Феліпе Буччоні

@FelipeBuccioni насправді це повинно бути egrepабо grep -Eабоsed -r
— SensorSmith

Для одного (першого) збігу додайте `| head -1` (без зворотних позначок), відповідно до цієї відповіді на інше питання.
— SensorSmith

1
grepповинен -m 1зупинитися після першого матчу.
— триплі

5

sedне розпізнає \d, використовуйте [[:digit:]]замість цього. Вам також потрібно буде вийти з режиму +або скористатися -rперемикачем (-E на OS X).

Зауважте, що це [0-9]працює також для арабсько-індуїстських цифр.


Я спробував sed -n '/[0-9]\+G[0-9]\+/p'. Тепер він просто друкує цілий рядок
— RanRag


5

Спробуйте замість цього:

echo "This is 02G05 a test string 20-Jul-2012" | sed 's/.* \([0-9]\+G[0-9]\+\) .*/\1/'

Але зверніть увагу, якщо на одному рядку є два шаблони, друкується 2-й.


Або загальніше останній, якщо є кілька збігів.
— триплі

0

Спробуйте використовувати рекстракцію . Це дозволить вам витягти текст за допомогою регулярного виразу та переформатувати його.

Приклад:

$ echo "This is 02G05 a test string 20-Jul-2012" | ./rextract '([\d]+G[\d]+)' '${1}'

2G05

Якщо для цього використовується стандартний регулярний вираз, квадратні дужки навколо \dабсолютно непотрібні.
— триплеє
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.