как использовать sed, awk или gawk для печати только того, что соответствует?
Я вижу много примеров и справочных страниц о том, как делать такие вещи, как поиск и замена с помощью sed, awk или gawk.
но в моем случае, у меня есть регулярное выражение, которое я хочу запустить на текстовый файл для извлечения определенного значения. Я не хочу делать поиск и замену. Это называется из Баша. Давайте возьмем пример:
пример регулярного выражения:
.*abc([0-9]+)xyz.*
пример входного файла:
a
b
c
abc12345xyz
a
b
c
как просто, как это звучит, я не могу выясните, как правильно вызвать sed/awk/gawk. То, что я надеялся сделать, это из моего сценария bash:
myvalue=$( sed <...something...> input.txt )
вещи, которые я пробовал включать:
sed -e 's/.*([0-9]).*/1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/1/g' example.txt # extracts nothing
10 ответов:
мой
sed
(Mac OS X) не работал с+
. Я пытался*
вместо этого и я добавилp
тег для печати матч:sed -n 's/^.*abc\([0-9]*\)xyz.*$//p' example.txt
для сопоставления хотя бы одного числового символа без
+
, Я хотел бы использовать:sed -n 's/^.*abc\([0-9][0-9]*\)xyz.*$//p' example.txt
вы можете использовать sed для этого
sed -rn 's/.*abc([0-9]+)xyz.*//gp'
-n
не печатайте полученную строку-r
это делает его так, что у вас нет побега группы захвата parens()
.матч группы захвата
/g
глобальные матч/p
печатать результатя написал инструмент для себя, что делает это проще!--9-->
rip 'abc(\d+)xyz' ''
Я использую
perl
чтобы сделать это проще для себя. например,perl -ne 'print if /.*abc([0-9]+)xyz.*/'
это работает Perl, тег указывает Perl читать по одной строке за раз из STDIN и выполнять код. Элемент
-e
параметр указывает инструкцию для запуска.инструкция запускает регулярное выражение на строке read, и если оно совпадает, выводит содержимое первого набора скобок (
).
вы можете сделать это несколько имен файлов в конец. например,
perl -ne 'print if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt
если ваша версия
grep
поддерживает это, вы могли бы использовать печати только часть любой строки, которая соответствует регулярное выражение.если нет, то вот лучшая
sed
я мог бы придумать:sed -e '/[0-9]/!d' -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'
... который удаляет / пропускает без цифр и для остальных строк удаляет все начальные и конечные нецифровые символы. (Я только предполагаю, что ваше намерение состоит в том, чтобы извлечь число из каждой строки, которая содержит один.)
проблема с чем-то вроде:
sed -e 's/.*\([0-9]*\).*/&/'
.... или
sed -e 's/.*\([0-9]*\).*//'
... это что
sed
поддерживает только" жадный " матч ... Итак, первое .* будет соответствовать остальной части линии. Если мы не можем использовать отрицательный класс символов для достижения не жадного соответствия ... или версияsed
С Perl-совместимыми или другими расширениями для его регулярных выражений мы не можем извлечь точное соответствие шаблона из пространства шаблонов (линия).
можно использовать
awk
Сmatch()
для доступа к захваченной группе:$ awk 'match(, /abc([0-9]+)xyz/, matches) {print matches[1]}' file 12345
это пытается соответствовать шаблону
abc[0-9]+xyz
. Если это так, он сохраняет свои срезы в массивеmatches
, чей первый элемент блока[0-9]+
. Так какmatch()
возвращает позицию символа или индекс, где начинается эта подстрока (1, если она начинается в начале строки) запускает
С
grep
вы можно использовать просмотром назад и посмотри вперед:$ grep -oP '(?<=abc)[0-9]+(?=xyz)' file 12345 $ grep -oP 'abc\K[0-9]+(?=xyz)' file 12345
это проверяет шаблон
[0-9]+
когда это происходит в пределахabc
иxyz
и просто печатает цифры.
perl-самый чистый синтаксис, но если у вас нет perl (не всегда там, я понимаю), то единственный способ использовать gawk и компоненты регулярного выражения-использовать функцию gensub.
gawk '/abc[0-9]+xyz/ { print gensub(/.*([0-9]+).*/,"\1","g"); }' < file
выход образца входного файла будет
12345
Примечание: gensub заменяет все регулярное выражение (между//), поэтому вам нужно поставить.* до и после ([0-9]+), чтобы избавиться от текста до и после числа, замена.
если вы хотите выбрать строки, то удалите биты, которые вы не хотите:
egrep 'abc[0-9]+xyz' inputFile | sed -e 's/^.*abc//' -e 's/xyz.*$//'
Он в основном выбирает строки, которые вы хотите с
egrep
а потом используетsed
для удаления битов до и после числа.вы можете увидеть это в действии здесь:
pax> echo 'a b c abc12345xyz a b c' | egrep 'abc[0-9]+xyz' | sed -e 's/^.*abc//' -e 's/xyz.*$//' 12345 pax>
обновление: очевидно, что если вы на самом деле ситуация более сложная, REs нужно будет мне изменить. Например, если у вас всегда было одно число, похороненное в пределах нуля или более без цифр в начале и конце:
egrep '[^0-9]*[0-9]+[^0-9]*$' inputFile | sed -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'
вы можете сделать это с оболочкой
while read -r line do case "$line" in *abc*[0-9]*xyz* ) t="${line##abc}" echo "num is ${t%%xyz}";; esac done <"file"