Как извлечь шаблоны из файла и заполнить их массивом bash? - PullRequest
1 голос
/ 12 июня 2019

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

Что является лучшимспособ достижения этого?

Я пытаюсь сделать это с помощью sed.И проблема, с которой я сталкиваюсь, состоит в том, что шаблоны могут иметь новые строки, и эти новые строки должны быть рассмотрены, например:

Содержимое файла:

"My name 
is XXX"
"My name is YYY"
"Today
is
the "

Когда я извлекаю все шаблоны между двойными кавычками, включаяв двойных кавычках вывод первого вхождения должен быть:

"My name
is XXX"

Ответы [ 3 ]

1 голос
/ 12 июня 2019

заполнить массив всеми вхождениями шаблона

Сначала преобразуйте ваш файл, чтобы получить значимый разделитель, напр.нулевой байт, с отл.GNU sed с переключателем -z:

sed -z 's/"\([^"]*\)"[^"]*/\1\00/g'

Я добавил [^"]* в конце, чтобы символы, не находящиеся между ", были удалены.

После этого он становитсяболее тривиально разобрать это.

Вы можете получить первый элемент с помощью:

head -z -n1

Или отсортировать и посчитать вхождения:

sort -z | uniq -z -c

Или загрузить в массив с помощью bash's maparray:

maparray -d '' -t arr < <(<input sed -z 's/"\([^"]*\)"[^"]*/\1\00/'g))

В качестве альтернативы вы можете использовать ex.$'\01' в качестве разделителя, пока он уникален, становится просто анализировать такие данные в bash.

Обработка таких потоков довольно сложна в bash.Вы не можете установить значение переменной в оболочке со встроенным нулевым байтом.Также ожидайте иногда предупреждения о подстановках команд.Обычно при обработке данных с произвольными байтами я конвертирую их с xxd -p в обычный ascii и обратно с xxd -r -p.С этим становится проще.

Будет выведен следующий скрипт:

cat <<'EOF' >input
"My name
is XXX"
"My name is YYY"
"Today
is
the "
EOF

sed -z 's/"\([^"]*\)"[^"]*/\1\x00/g' input > input_parsed

echo "##First element is:"
printf '"'
<input_parsed head -z -n1 
printf '"\n'

echo "##Elemets count are:"
<input_parsed sort -z | uniq -z -c

echo
echo "##The array is:"
mapfile -d '' -t arr <input_parsed
declare -p arr

(форматирование немного отключено из-за не разделенного на новую строку вывода из uniq):

##First element is:
"My name
is XXX"
##Elemets count are:
      1 My name
is XXX      1 My name is YYY      1 Today
is
the 
##The array is:
declare -a arr=([0]=$'My name\nis XXX' [1]="My name is YYY" [2]=$'Today\nis\nthe ')

Проверено на repl.it .

0 голосов
/ 13 июня 2019

Sed может извлечь желаемый шаблон с или без перевода строки.Но если вы хотите сохранить несколько результатов в массиве bash, может быть проще использовать регулярное выражение bash.
Затем попробуйте следующее:

lines=$(< "file")                   # slurp all lines
re='"[^"]+"'                        # regex to match substring between double quotes
while [[ $lines =~ ($re)(.*) ]]; do
    array+=("${BASH_REMATCH[1]}")   # push the matched pattern to the array
    lines=${BASH_REMATCH[2]}        # update $lines with the remaining part
done

# report the result
for (( i=0; i<${#array[@]}; i++ )); do
    echo "$i: ${array[$i]}"
done

Вывод:

0: "My name
is XXX"
1: "My name is YYY"
2: "Today
is
the "
0 голосов
/ 12 июня 2019

Это может быть то, что вы ищете, в зависимости от ответов на вопросов, которые я оставил в комментарии :

$ readarray -d '' -t arr < <(grep -zo '"[^"]*"' file)

$ printf '%s\n' "${arr[0]}"
"My name
is XXX"

$ declare -p arr
declare -a arr=([0]=$'"My name \nis XXX"' [1]="\"My name is YYY\"" [2]=$'"Today\nis\nthe "')

Использует GNU grep для -z.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...