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

1

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 eu quero de um monte de arquivos (foo * .txt). Quando tento imprimir o nome do arquivo (em uma coluna do arquivo csv) e o número (no próximo coloum 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

Isto imprime os nomes dos arquivos no terminal. O arquivo csv contém os números que eu quero. Como esse código pode ser modificado para que o nome do arquivo seja impresso em uma coloumn 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 dos arquivos foo_01_s.txt, foo_02_s.txt, foo_03_s.txt ..... foo_100_s.txt. Se eu quiser extrair informação (usando os comentários acima), o último arquivo (foo_100_s.txt) não vem depois de foo_99_s.txt.

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

    
por phenomenon 29.09.2017 / 07:59

1 resposta

2

Você tem que entender que o >> só redirecionará a parte do comando atual - basicamente apenas o número que é o resultado do comando começando com grep e canalizado algumas vezes. echo $file é um comando separado (você usa ; ) e, portanto, normalmente direciona para stdout. Tudo o 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ê quiser "versão" classificar seus arquivos (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 ~ 1000 arquivos), isso deve ser bom.

EDITAR

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

file1 1
      2
      3

Basta soltar o echo e 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,\)} else {printf("%-20s %-5s\n","",$2)}}'
done > bar2.csv

Eu deixei awk fazer a impressão para mim. Usando -v me permite passar uma variável em f . Para a impressão familiarize-se com a sintaxe printf (você pode usar man printf no shell. Basicamente, estou assumindo dois campos, um com 20, o outro 5 e um espaço entre. O sinal negativo à esquerda justifica. brincar com isso. Isso teria corrigido seu problema inicial, já que agora você pode canalizar aquela única linha.

Se você quer que o arquivo seja apenas:

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

você pode largar a declaração if no meu awk ou deixar a solução inicial com o echo, mas use

echo -n "$file,"

onde -n garante que nenhuma nova linha seja impressa.

    
por 29.09.2017 / 10:22

Tags