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

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

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

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

***********
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, а не целый блок.

Ответы

Ответ 1

Я удивлен, увидев здесь не родное решение 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

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

Ответ 2

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

#!/bin/bash
shopt -s extglob
entry=""
while read line
do
    case $line in 
        +(\*))
            # do something with $entry here
            entry=""
            ;;
        *)
            entry="$entry$line
"
            ;;
    esac
done

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

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

#!/bin/bash

foo() {
    echo record start:
    echo "[email protected]"
    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