Как произвести только полученные группы с sed?

Есть ли любой способ сказать sed производить только полученные группы? Например, учитывая вход:

This is a sample 123 text and some 987 numbers

и шаблон:

/([\d]+)/

Я мог получить только 123 и 987 выводов путем, отформатированным обратными ссылками?

258
задан Jaime Hablutzel 11 April 2019 в 17:50
поделиться

5 ответов

Ключ к тому, чтобы заставить это работать, - это указать sed, чтобы исключить то, что вы не хотите выводить, а также указать то, что вы хотите.

string='This is a sample 123 text and some 987 numbers'
echo "$string" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'

Это говорит:

  • не печатать по умолчанию каждую строку (-n)
  • исключить ноль или более нецифр
  • включить одну или более цифр
  • исключить одну или более нецифр
  • включить одну или более цифр
  • исключить ноль или более нецифр
  • вывести подстановку (p)

В общем, в sed вы захватываете группы с помощью круглых скобок и выводите то, что вы захватили, используя обратную ссылку:

echo "foobarbaz" | sed 's/^foo\(.*\)baz$/\1/'

выведет "bar". Если вы используете -r (-E для OS X) для расширенного regex, вам не нужно раскрывать круглые скобки:

echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'

Может быть до 9 групп захвата и их обратных ссылок. Обратные ссылки нумеруются в порядке появления групп, но они могут использоваться в любом порядке и могут повторяться:

echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'

выводит "a bar a".

Если у вас есть GNU grep (он также может работать в BSD, включая OS X):

echo "$string" | grep -Po '\d+'

или такие варианты, как:

echo "$string" | grep -Po '(?<=\D )(\d+)'

Опция -P включает Perl-совместимые регулярные выражения. См. man 3 pcrepattern или man 3 pcresyntax.

308
ответ дан 23 November 2019 в 02:41
поделиться

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

См. здесь , где приведены примеры и подробности

52
ответ дан 23 November 2019 в 02:41
поделиться

Попробуйте

sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"

Я получил это под cygwin:

$ (echo "asdf"; \
   echo "1234"; \
   echo "asdf1234adsf1234asdf"; \
   echo "1m2m3m4m5m6m7m8m9m0m1m2m3m4m5m6m7m8m9") | \
  sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"

1234
1234 1234
1 2 3 4 5 6 7 8 9
$
5
ответ дан 23 November 2019 в 02:41
поделиться

вы можете использовать grep

grep -Eow "[0-9]+" file
30
ответ дан 23 November 2019 в 02:41
поделиться

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

Если у вас есть sed с расширением GNU, позволяющим вставлять новую строку в пространство шаблонов, одно предложение:

> set string = "This is a sample 123 text and some 987 numbers"
>
> set pattern = "[0-9][0-9]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
123
987
> set pattern = "[a-z][a-z]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
his
is
a
sample
text
and
some
numbers

Эти примеры с tcsh (да, я знаю ] это неправильная оболочка) с CYGWIN. (Изменить: для bash удалите набор и пробелы вокруг =.)

9
ответ дан 23 November 2019 в 02:41
поделиться
Другие вопросы по тегам:

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