Sed: печать только соответствующая группа

Я хочу взять последние два числа (один 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' 

Как я могу напечатать только часть строки, которая соответствует регулярному выражению в группе?

Ответ 1

Совместите всю строку, поэтому добавьте .* в начало вашего регулярного выражения. Это приводит к замене всей строки на содержимое группы

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

Ответ 2

grep - это правильный инструмент для извлечения.

используя ваш пример и ваше регулярное выражение:

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

Ответ 3

И для еще одного варианта, я бы пошел с awk!

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

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

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

Ответ 4

Команда cut предназначена именно для этой ситуации. Он будет "разрезан" на любом разделителе, и тогда вы сможете указать, какие куски следует выводить.

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

Результатом будет вывод: 2 3.4

-d устанавливает разделитель

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

Ответ 5

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

# 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