как использовать sed, awk или gawk для печати только того, что сопоставлено?
Я вижу много примеров и справочных страниц о том, как делать такие вещи, как поиск и замена с помощью sed, awk или gawk.
но в моем случае, у меня есть регулярное выражение, которое я хочу запустить на текстовый файл для извлечения определенного значения. Я не хочу делать поиск и замену. Это называется от bash. Приведем пример:
пример регулярного выражения:
.*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) не работал с +
. Я пытался!--4--> вместо этого я добавил 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,-n
опция инструктирует Perl читать по одной строке за раз из STDIN и выполнять код. The -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, если она начинается в начале строки) запускает print
действие.
С grep
вы можно использовать look-behind и look-ahead:
$ 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"
по awk. Я бы использовал следующий скрипт:
/.*abc([0-9]+)xyz.*/ {
print ;
next;
}
{
/* default, do nothing */
}