как использовать 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
93 голоса | спросил Stéphane 14 62009vEurope/Moscow11bEurope/MoscowSat, 14 Nov 2009 11:34:14 +0300 2009, 11:34:14

10 ответов


0

Мой sed (Mac OS X) не работал с +. Вместо этого я попробовал * и добавил p тег для печати совпадения:

sed -n 's/^.*abc\([0-9]*\)xyz.*$/\1/p' example.txt

Для сопоставления хотя бы одного числового символа без + я бы использовал:

sed -n 's/^.*abc\([0-9][0-9]*\)xyz.*$/\1/p' example.txt
ответил mouviciel 14 62009vEurope/Moscow11bEurope/MoscowSat, 14 Nov 2009 11:50:20 +0300 2009, 11:50:20
0

Вы можете использовать sed для этого

 sed -rn 's/.*abc([0-9]+)xyz.*/\1/gp'
  • -n не печатать полученную строку
  • -r это делает вас такими, что у вас нет выхода из группы захвата группы ().
  • \1 совпадение группы захвата
  • /g глобальное соответствие
  • /p распечатать результат

Я написал для себя инструмент , который облегчает эту задачу

rip 'abc(\d+)xyz' '$1'
ответил Ilia Choly 3 FebruaryEurope/MoscowbWed, 03 Feb 2016 22:39:12 +0300000000pmWed, 03 Feb 2016 22:39:12 +030016 2016, 22:39:12
0

Я использую perl, чтобы мне было проще. например.

perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/'

Это запускает Perl, опция -n указывает Perl читать по одной строке за раз из STDIN и выполнять код. Параметр -e указывает команду для выполнения.

Инструкция выполняет регулярное выражение для прочитанной строки и, если она совпадает, печатает содержимое первого набора скобок ($1 ).

Вы можете сделать это, также будет несколько имен файлов в конце. например.

perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt

ответил PP. 14 62009vEurope/Moscow11bEurope/MoscowSat, 14 Nov 2009 11:44:04 +0300 2009, 11:44:04
0

Если ваша версия grep поддерживает ее, вы можете использовать -o возможность печатать только часть любой строки, которая соответствует вашему регулярному выражению.

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

sed -e '/[0-9]/!d' -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'

... который удаляет /пропускает без цифр и, для оставшихся строк, удаляет все начальные и конечные нецифровые символы. (Я только предполагаю, что вы намереваетесь извлечь число из каждой строки, содержащей его).

Проблема с чем-то вроде:

sed -e 's/.*\([0-9]*\).*/&/' 

.... или

sed -e 's/.*\([0-9]*\).*/\1/'

... в том, что sed поддерживает только "жадное" совпадение ... поэтому первый. * будет соответствовать остальным линия. Если только мы не можем использовать отрицательный класс символов для достижения не жадного соответствия ... или версии sed с Perl-совместимым или другим Расширения его регулярных выражений, мы не можем извлечь точное совпадение с шаблоном пространства (линии).

ответил Jim Dennis 14 62009vEurope/Moscow11bEurope/MoscowSat, 14 Nov 2009 13:56:46 +0300 2009, 13:56:46
0

Вы можете использовать awk с match() для доступа к захваченной группе:

$ awk 'match($0, /abc([0-9]+)xyz/, matches) {print matches[1]}' file
12345

Это пытается соответствовать шаблону abc[0-9]+xyz. Если это так, он сохраняет свои фрагменты в массиве matches, первым элементом которого является блок [0-9]+. Поскольку match() возвращает позицию символа или индекс, где начинается эта подстрока (1, если она начинается в начале строки ) запускает действие print.


С помощью grep вы можете использовать упущение и упреждение:

$ grep -oP '(?<=abc)[0-9]+(?=xyz)' file
12345

$ grep -oP 'abc\K[0-9]+(?=xyz)' file
12345

Это проверяет шаблон [0-9]+, когда он встречается в abc и xyz и просто печатает цифры.

ответил fedorqui 22 PM000000120000001131 2016, 12:01:11
0

perl - это самый чистый синтаксис, но если у вас нет perl (не всегда, я так понимаю), тогда единственный способ использовать gawk и компоненты регулярного выражения - использовать функцию gensub.

gawk '/abc[0-9]+xyz/ { print gensub(/.*([0-9]+).*/,"\\1","g"); }' < file

выходной файл примера ввода будет

12345

Примечание: gensub заменяет все регулярные выражения (между //), поэтому вам нужно поставить. * до и после ([0-9] +), чтобы избавиться от текста до и после числа в подстановке .

ответил Mark Lakata 30 AMpTue, 30 Apr 2013 00:21:53 +040021Tuesday 2013, 00:21:53
0

Если вы хотите выделить строки, удалите ненужные биты:

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> 

Обновление: очевидно, если вы на самом деле более сложная ситуация, RE нужно будет изменить. Например, если у вас всегда было одно число, скрытое в пределах нуля или более нечисловых значений в начале и конце:

egrep '[^0-9]*[0-9]+[^0-9]*$' inputFile | sed -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'
ответил paxdiablo 14 62009vEurope/Moscow11bEurope/MoscowSat, 14 Nov 2009 11:46:20 +0300 2009, 11:46:20
0

вы можете сделать это с помощью оболочки

while read -r line
do
    case "$line" in
        *abc*[0-9]*xyz* ) 
            t="${line##abc}"
            echo "num is ${t%%xyz}";;
    esac
done <"file"
ответил ghostdog74 28 62009vEurope/Moscow11bEurope/MoscowSat, 28 Nov 2009 04:58:22 +0300 2009, 04:58:22
0

Для awk. Я бы использовал следующий скрипт:

/.*abc([0-9]+)xyz.*/ {
            print $0;
            next;
            }
            {
            /* default, do nothing */
            }
ответил Pierre 14 62009vEurope/Moscow11bEurope/MoscowSat, 14 Nov 2009 11:54:58 +0300 2009, 11:54:58
0
gawk '/.*abc([0-9]+)xyz.*/' file
ответил ghostdog74 14 62009vEurope/Moscow11bEurope/MoscowSat, 14 Nov 2009 12:18:02 +0300 2009, 12:18:02

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132