sed: друкувати лише відповідну групу


133

Я хочу захопити два останніх числа (один int, один float; далі - необов’язковий пробіл) і надрукувати лише їх.

Приклад:

foo bar <foo> bla 1 2 3.4

Слід надрукувати:

2 3.4

Поки що у мене є таке:

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/replacement/p' 

дасть мені

foo bar <foo> bla 1 replacement

Однак якщо я спробую замінити його групою 1, друкується весь рядок.

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

Як я можу надрукувати лише той розділ рядка, який відповідає регулярному вираженню в групі?

Відповіді:


138

Зрівняйте весь рядок, тому додайте .*на початку свого регулярного вираження. Це призводить до того, що весь рядок буде замінено вмістом групи

echo "foo bar <foo> bla 1 2 3.4" |
 sed -n  's/.*\([0-9][0-9]*[\ \t][0-9.]*[ \t]*$\)/\1/p'
2 3.4

38
Мені довелося додати параметр -rабо - --regexp-extension`, інакше я отримував invalid reference \1 on помилку RHS команди команди '.
Даніель Соколовський

15
@DanielSokolowski Я думаю , ви отримаєте цю помилку , якщо ви використовуєте (і )замість \(і \).
Даніель Дарабос

3
Також не забудьте додати .*до кінця регулярного вираження, якщо рядок, яку ви бажаєте витягти, не завжди знаходиться в кінці рядка.
Teemu Leisti

3
Це не спрацює для мене, тому що .*жадібний та сед не має жадібного.*?
sondra.kinsey

@DanielDarabos Просто згадайте, що (і )не призведе до помилок в ubuntu 16.04. Тому я вважаю, що цей коментар застарів.
Li haonan

72

grep - це правильний інструмент для видобутку.

використовуючи ваш приклад та ваш регулярний вираз:

kent$  echo 'foo bar <foo> bla 1 2 3.4'|grep -o '[0-9][0-9]*[\ \t][0-9.]*[\ \t]*$'
2 3.4

12
відмінно підходить для всієї групи, хоча для окремих груп потрібен sed
jozxyqk

grep -o не портує на системи, на яких працює msysgit, але sed.
Чемберлен

Дивіться питання, пов’язане з @jozxyqk, щоб отримати відповідь, яка використовує погляд вперед та позаду, щоб вирішити це з грепом.
Йоахім Брейтнер

Ви можете витягти групу з шаблону за допомогою трубних grep -oдзвінків. stackoverflow.com/a/58314379/117471
Bruno Bronosky

12

І для ще одного варіанту я б пішов із дивним!

echo "foo bar <foo> bla 1 2 3.4" | awk '{ print $(NF-1), $NF; }'

Це розділить вхідні дані (я тут використовую STDIN, але ваш вклад може легко бути файлом) на пробіли, а потім роздрукувати поле останнє, але одне, а потім останнє. У $NFзмінних містять кількість полів виявлено після вибуху на просторах.

Перевага цього в тому, що не має значення, чи зміниться те, що передує останнім двом полям, поки ви хочете лише коли-небудь останні два, вони продовжуватимуть працювати.


3

Команда cut розрахована саме на цю точну ситуацію. Він "вирізається" на будь-якому роздільнику, і тоді ви можете вказати, які шматки слід вивести.

Наприклад: echo "foo bar <foo> bla 1 2 3.4" | cut -d " " -f 6-7

Це призведе до виходу: 2 3.4

-d встановлює роздільник

-f вибирає діапазон "полів" для виведення, у цьому випадку це 6-й-7-й фрагменти вихідної рядки. Ви також можете вказати діапазон у списку, наприклад 6,7.


Щоб надрукувати лише певні колонки, перейдіть доawk '{ print $2" "$6 }'
Нуреттін

@nurettin Я думаю, що ваш коментар може бути призначений для однієї з відповідей awk.
carlin.scott

Я спробував скоротити, коли я відвідав цю сторінку і зрозумів, що це обмеження, і вирішив написати більш узагальнену версію в awk замість цього, як коментар, щоб покращити якість цієї публікації.
Нуреттін

1
Так, я думаю, що це належить до іншої відповіді, що стосується awk. Команда скоротити виконувати те, що ви написали:cut -d " " -f 2,6
carlin.scott

ах, я цього не знав, я думав, що ти можеш давати лише діапазони. Дякую за це.
Нуреттін

2

Я погоджуюся з @kent, що це добре підходить grep -o. Якщо вам потрібно витягти групу в рамках шаблону, ви можете зробити це з 2-ою грепою.

# To extract \1 from /xx([0-9]+)yy/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'xx[0-9]+yy' | grep -Eo '[0-9]+'
123
4

# To extract \1 from /a([0-9]+)b/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'a[0-9]+b' | grep -Eo '[0-9]+'
678
9
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.