Есть ли любой способ сказать sed
производить только полученные группы? Например, учитывая вход:
This is a sample 123 text and some 987 numbers
и шаблон:
/([\d]+)/
Я мог получить только 123 и 987 выводов путем, отформатированным обратными ссылками?
Ключ к тому, чтобы заставить это работать, - это указать 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
.
У Sed есть до девяти запомненных шаблонов, но вам нужно использовать экранированные круглые скобки, чтобы запомнить части регулярного выражения.
См. здесь , где приведены примеры и подробности
Попробуйте
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
$
вы можете использовать grep
grep -Eow "[0-9]+" file
Я считаю, что шаблон, приведенный в вопросе, был приведен только в качестве примера, и цель состояла в том, чтобы сопоставить любой шаблон.
Если у вас есть 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 удалите набор и пробелы вокруг =.)