eu tenho um arquivo que contém vários parágrafos que usam colchetes como separadores como este
{
KEYWORD
a = 1
b = 2
c = 3
}
{
d = 4
KEYWORD
e = 5
f = 6
}
Gostaria de fazer um loop em cada parágrafo e atribuí-lo a uma variável $foo enquanto preserva as quebras de linha, de modo que echo $foo resultará na saída do parágrafo em formato de várias linhas. Depois de processar a saída de $foo, por exemplo, echo $foo | grep bar
o programa deve ir para o próximo parágrafo e sobrescrever $foo
Tenho brincado com o awk porque parece ser a melhor ferramenta neste caso, mas não consigo descobrir como fazer algum tipo de loop while para poder processar cada parágrafo separadamente.
O que tenho até agora é:
grep -Pzo "{[^}]*KEYWORD[^}]*}" FILENAME | awk "/{/{flag=1;
paragraph=\"\"; next} /}/{flag=0; print paragraph} flag {paragraph =
paragraph \$0 \"\\n\"}"
isso produz parágrafos legais como este
KEYWORD
a = 1
b = 2
c = 3
d = 4
KEYWORD
e = 5
f = 6
O que estou travando é que quero realizar outras ações no parágrafo 1 antes de passar para o parágrafo 2.
O mais próximo que cheguei de uma solução foi escrever os resultados em um array, mas perdi o parágrafo e tudo estava em uma linha e não consegui fazer o processamento pós-correspondência que queria.
ATUALIZAR:
No espírito de que existe mais de uma maneira de fazer isso e se você só tiver um martelo então tudo parece um prego, ofereço minha solução:
# Read paragraphs into an array
while IFS= read -r paragraph; do
paragraphs+=("$paragraph")
done < <(awk '/\{/{flag=1; paragraph=""; next} /\}/{flag=0; print paragraph} flag {paragraph = paragraph $0}' testoutput.txt)
# Print each paragraph separately
for ((i=0; i<${#paragraphs[@]}; i++)); do
# Assign each paragraph to a variable using eval
eval "foo_$i=\"${paragraphs[$i]}\""
# Print the variable recreating the line breaks
echo "Variable foo_$i:"
eval "echo \"\$foo_$i\"|sed 's/\s\{2,\}/\n/g'"
done
A chave para o sucesso foi usar sed 's/\s\{2,\}/\n/g'
e não \s
ou \s+
um ou mais versus dois ou mais.
Aqui está uma abordagem usando um
while
loop nas linhas do arquivo de entrada. As linhas são lidasread -r
em uma variávelline
. Se for a{
, redefina a variávelfoo
. Se for um}
, faça algo com$foo
(aqui estou imprimindo seu conteúdo bruto, seu comprimento e algum texto estático). Em qualquer outro caso, anexe o conteúdo deline
ao conteúdo atual defoo
.Modificando o script atual do OP
awk
para gerar cada parágrafo em uma única linha onde os linefeeds incorporados (\n
) são substituídos pelos caracteres literais\
+n
:Executando isso na entrada de amostra:
Podemos então alimentá-los com
bash
o builtinprintf
para preencher a variávelfoo
:NOTA:
printf -v
requerbash 3.1+
Isso gera:
Uma ideia para
mapfile
ler os 'parágrafos' em uma matriz:Existem alguns itens de interesse:
0
2
), pois ela captura tudo após a última}
no arquivo\n
que precisaremos removerLevando essas questões em consideração... um
bash/for
loop para processar um 'parágrafo' por vezIsso gera:
NOTA: Se o arquivo não estiver formatado exatamente como mostrado no exemplo (por exemplo, o arquivo real contém linhas em branco; há espaço em branco extra antes/depois dos caracteres
{
e}
, isso pode não funcionar como esperado e/ou pode ser necessário executar alguns substituições de parâmetros adicionais para massagearfoo
no formato desejado.Um exemplo de algumas substituições de parâmetros adicionais para remover o
{\n
and}\n
:Isso gera:
O que eu faria:
A ideia é dividir a saída nos caracteres
{\n
para usar o padrão multilinha emawk
.