Eu tenho um script bash super complicado que extrai resultados de um arquivo de saÃda grande (produzido em uma máquina LINUX, só para o caso de ser relevante). Como parte desse processo, eu uso combinações de grep, head, tail, etc. que extraem subseções desse arquivo maior; essa subseção de texto é então salva em um arquivo temporário que é então processado posteriormente. Eu produzi um exemplo mais simples aqui para que eu possa enquadrar minha pergunta, que é:
Como posso evitar a necessidade de salvar neste arquivo temporário?
O que eu gostaria de fazer é, em vez de salvar esta subseção de texto em um arquivo temporário, salvar a subseção de dados (incluindo retornos de carro) em uma variável bash que pode então ser processada posteriormente.
O problema é que os scripts bash que estou escrevendo não 'vêem' os retornos de carro. No meu exemplo abaixo, tenho um arquivo 'exampledata.data' contendo o seguinte texto:
START_BLOCK #1
line a b c
line b
END_BLOCK #1
START_BLOCK #2
Line 1 2
Line 2 7
Line 3
Line 4
END_BLOCK #2
START_BLOCK #3
Line x s d e f
END_BLOCK #3
Meu script original (que salva em um arquivo temporário) funciona como esperado, com o comando awk exibindo corretamente o segundo token para todas as linhas dentro de cada 'bloco':
#!/bin/bash
file="examplefile.data" # File to process
totblock=`grep "START_BLOCK" $file | wc -l` # Determine number of blocks of data in file
# Current implementation - which works
for ((l=1; $l<=${totblock}; l++)); do # Loop through each block of data
echo "BLOCK "$l
# display file contents -> extract subsection of data for current block -> Remove top and bottom -> Save to temporary file
cat $file | \
sed -n '/START_BLOCK #'${l}'/,/END_BLOCK #'${l}'/p' | \
grep -Ev "START|END" > TEMPFILE
# Perform some rudimentary processing on this temporary file to check the overall process is working
awk '{print $2}' TEMPFILE
done
rm TEMPFILE
Se eu então tentar salvar o que teria sido salvo em TEMPFILE para uma variável bash (bashvar), todos os retornos de carro serão perdidos, resultando em uma linha longa. Como consequência, o comando awk essencialmente mostra apenas o 2º token da primeira linha, o que não é o que eu quero:
#!/bin/bash
file="examplefile.data" # File to process
totblock=`grep "START_BLOCK" $file | wc -l` # Determine number of blocks of data in file
# New implementation with the aim to avoid the need to write to a temporary file (TEMPFILE)
for ((l=1; $l<=${totblock}; l++)); do
echo "BLOCK "$l
# As above but rather than piping the output to a file, save it to a bash-variable
bashvar=`cat $file | \
sed -n '/START_BLOCK #'${l}'/,/END_BLOCK #'${l}'/p' | \
grep -Ev "START|END"`
# Perform the same rudimentary test to confirm the overall process is working
echo $bashvar | awk '{print $2}'
done
Primeiro de tudo, você realmente não quer fazer coisas assim no bash ou em qualquer outro shell. Use uma linguagem de programação real em vez disso. Será mais fácil, rápido e eficiente.
Dito isso, a razão pela qual isso não funciona para você é porque você não está citando a variável, então o shell aplica split + glob . Então, simplesmente mudar seu
echo
comando final para isso funcionaria:No entanto, há vários outros problemas e melhorias que você pode fazer aqui. O
grep
comando pode contar para você, sem necessidade dewc
. Você deve evitarvar=`command`
e usarvar=$(command)
em vez disso. Você deve citar todas as suas variáveis ​​. Usemktemp
para criar arquivos temporários (irrelevante se você quiser evitar arquivos, mas tenha isso em mente para a próxima vez). Evite codificar nomes de arquivo, use argumentos em vez disso. Usegrep -w
para garantir correspondências completas (para queNOT_A_START_BLOCK
não seja considerado uma correspondência paraSTART_BLOCK
). Você não precisa decat "$file" | sed
, você pode fazersed "$file"
diretamente. Não há necessidade de\
depois de um|
, você pode quebrar a linha no|
. Aqui está uma versão do seu script levando tudo isso em consideração:Note que isso seria realmente melhor em praticamente qualquer outra linguagem. Já que você está usando
awk
, por que não fazer tudo em awk?Eu sugiro que você poste uma nova pergunta, descreva o processamento real que você está fazendo e peça uma solução para fazer isso. Fazer loop em seções de um arquivo de texto no bash realmente não é uma ideia muito boa.