как использовать 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 */
}