Usando grep, awk e csv para extrair informações de arquivos de texto

Usando grep, awk e csv para extrair informações de arquivos de texto

Estou usando o código a seguir para extrair informações de vários arquivos de texto (foo*.txt).

for file in foo*.txt; do 
grep "some_text" $file | tail -n5 | awk '{print $2}' >> bar.csv
done

Este comentário imprime os números que desejo de vários arquivos (foo*.txt). Quando tento imprimir o nome do arquivo (em uma coluna do arquivo csv) e o número (na próxima coluna do arquivo csv), tentei seguir no Terminal.

for file in foo*.txt; do 
echo $file
grep "some_text" $file | tail -n5 | awk '{print $2}' >> bar2.csv 
done

Isso imprime os nomes dos arquivos no terminal. O arquivo csv contém os números que desejo. Como esse código pode ser modificado para que o nome do arquivo seja impresso em uma coluna e os números extraídos na próxima coluna do arquivo csv?

Outro problema neste código é o problema de classificação. Por exemplo, considere os nomes de arquivo foo_01_s.txt, foo_02_s.txt, foo_03_s.txt.....foo_100_s.txt. Se eu quiser extrair informações (usando os comentários acima), o último arquivo (foo_100_s.txt) não vem depois de foo_99_s.txt.

Uma solução usando Python/Perl também seria útil.

Responder1

Você tem que entender que >>irá redirecionar apenas a parte do comando atual - basicamente apenas o número que é o resultado do comando começando com grepe canalizado algumas vezes. echo $fileé um comando separado (você usa ;) e, portanto, normalmente direcionará para stdout. Tudo que você precisa fazer é redirecionar após todo o loop:

for file in foo*.txt; do 
    echo $file
    grep "some_text" $file | tail -n5 | awk '{print $2}'
done > bar2.csv

Se você deseja classificar seus arquivos por "versão" (este é o nome apropriado), você pode listá-los após a classificação:

for file in $(ls foo*.txt | sort -V); do

para executar algo pequeno rapidamente (alguns minutos para cerca de 1000 arquivos), isso deve servir.

EDITAR

Após seu comentário, existem algumas soluções. Acho que você quer:

file1 1
      2
      3

etc. Basta descartar echoe alterar a linha de eco:

for file in foo*.txt; do 
    grep "some_text" $file | tail -n5 | awk -v f=$file '{if(NR==1) {printf("%-20s %-5s\n",f,\$2)} else {printf("%-20s %-5s\n","",$2)}}'
done > bar2.csv

Deixei awkfazer a impressão para mim. Usar -vme permite passar uma variável em f. Para a impressão, familiarize-se com printfa sintaxe (você pode usar man printfno shell. Basicamente, estou assumindo dois campos, um com 20, o outro com 5 e um espaço entre eles. O sinal negativo justifica à esquerda. Você pode brincar com isso. Isso seria corrigiu seu problema inicial, já que agora você pode canalizar essa única linha.

Se você quiser que o arquivo seja apenas:

file1,1
file1,2
...
file2,1

você pode descartar ifminha awkdeclaração ou deixar a solução inicial com echo, mas use,

echo -n "$file,"

onde -ngarante que nenhuma nova linha seja impressa.

informação relacionada