Как я могу присвоить совпадение моего регулярного выражения переменной? - PullRequest
15 голосов
/ 08 августа 2009

У меня есть текстовый файл с различными записями в нем. Каждая запись заканчивается строкой, содержащей все звездочки.

Я бы хотел использовать команды оболочки для разбора этого файла и присвоения каждой записи переменной. Как я могу это сделать?

Вот пример входного файла:

***********
Field1
***********
Lorem ipsum
Data to match
***********
More data
Still more data
***********

Вот как выглядит мое решение:

#!/bin/bash
for error in `python example.py | sed -n '/.*/,/^\**$/p'`
do
    echo -e $error
    echo -e "\n"
done

Однако это просто присваивает каждому слову в сопоставленном тексте значение $ error, а не целый блок.

Ответы [ 5 ]

27 голосов
/ 08 августа 2009

Я удивлен, что не вижу здесь собственного решения bash. Да, у bash есть регулярные выражения. Вы можете найти много случайной документации в Интернете, особенно если вы включите «bash_rematch» в свой запрос или просто посмотрите страницы руководства. Вот глупый пример, взятый из здесь и слегка модифицированный, который печатает все совпадения и каждое захваченное совпадение для регулярного выражения.

if [[ $str =~ $regex ]]; then
    echo "$str matches"
    echo "matching substring: ${BASH_REMATCH[0]}"
    i=1
    n=${#BASH_REMATCH[*]}
    while [[ $i -lt $n ]]
    do
        echo "  capture[$i]: ${BASH_REMATCH[$i]}"
        let i++
    done
else
    echo "$str does not match"
fi

Важным битом является то, что расширенный тест [[ ... ]] с использованием сравнения регулярных выражений =~ сохраняет все совпадения в ${BASH_REMATCH[0]}, а захваченные совпадения в ${BASH_REMATCH[i]}.

1 голос
/ 08 августа 2009

Попробуйте заключить в команду двойные кавычки.

#!/bin/bash
for error in "`python example.py | sed -n '/.*/,/^\**$/p'`"
do
    echo -e $error
    echo -e "\n"
done
1 голос
/ 08 августа 2009

Если вы хотите сделать это в Bash, вы можете сделать что-то вроде следующего. Вместо регулярных выражений он использует globbing (опция оболочки extglob включает расширенное сопоставление с образцом, поэтому мы можем сопоставить строку, состоящую только из звездочек.)

#!/bin/bash
shopt -s extglob
entry=""
while read line
do
    case $line in 
        +(\*))
            # do something with $entry here
            entry=""
            ;;
        *)
            entry="$entry$line
"
            ;;
    esac
done
0 голосов
/ 08 августа 2009

Разделение записей в (ba) sh не так просто, но это можно сделать с помощью IFS для разделения на отдельные символы (просто установите IFS = '*' перед циклом for, но это создает несколько пустых записей и проблематично, если таковые имеются запись содержит «*»). Очевидное решение - использовать perl или awk и использовать RS для разделения ваших записей, поскольку эти инструменты предоставляют более совершенные механизмы для разделения записей. Гибридное решение - использовать Perl для разделения записей и заставить Perl вызывать вашу функцию bash с нужной вам записью. Например:

#!/bin/bash

foo() {
    echo record start:
    echo "$@"
    echo record end
}
export -f foo

perl -e "$/='********'; while(<>){chomp;system( \"foo '\$_'\" )}" << 'EOF'
this is a 2-line
record
********
the 2nd record
is 3 lines
long
********
a 3rd * record
EOF

Это дает следующий вывод:

record start:
this is a 2-line
record

record end
record start:

the 2nd record
is 3 lines
long

record end
record start:

a 3rd * record

record end
0 голосов
/ 08 августа 2009

в зависимости от того, что вы хотите сделать с переменными

awk '
f && /\*/{print "variable:"s;f=0}
/\*/{ f=1 ;s="";next}
f{
   s=s" "$0
}' file

выход:

# ./test.sh
variable: Field1
variable: Lorem ipsum Data to match
variable: More data Still more data

вышесказанное просто распечатывает их. если хотите, сохраните в массиве для последующего использования ... например, массив [++ d] = s

...