Usando grep, awk y csv para extraer información de archivos de texto

Usando grep, awk y csv para extraer información de archivos de texto

Estoy usando el siguiente código para extraer información de un montón de archivos de texto (foo*.txt).

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

Este comentario imprime los números que quiero de un montón de archivos (foo*.txt). Cuando intento imprimir tanto el nombre del archivo (en una columna del archivo csv) como el número (en la siguiente columna del archivo csv), intenté seguirlo en la Terminal.

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

Esto imprime los nombres de los archivos en la terminal. El archivo csv contiene los números que quiero. ¿Cómo se puede modificar este código para que el nombre del archivo se imprima en una columna y los números extraídos en la siguiente columna del archivo csv?

Otro problema en este código es el problema de clasificación. Por ejemplo, considere los nombres de archivos foo_01_s.txt, foo_02_s.txt, foo_03_s.txt.....foo_100_s.txt. Si quiero extraer información (usando los comentarios anteriores), el último archivo (foo_100_s.txt) no viene después de foo_99_s.txt.

La solución que utiliza Python/Perl también sería útil.

Respuesta1

Debe comprender que >>solo redirigirá la parte del comando actual; básicamente, solo el número que es el resultado del comando que comienza con grepy se transmite varias veces. echo $filees un comando separado (usted usa ;) y, por lo tanto, normalmente lo dirigirá a la salida estándar. Todo lo que necesitas hacer es redirigir después de todo el ciclo:

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

Si desea ordenar sus archivos por "versión" (este es el nombre apropiado), puede enumerarlos después de ordenarlos:

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

para ejecutar algo pequeño rápidamente (unos pocos minutos para ~1000 archivos), esto debería estar bien.

EDITAR

Siguiendo tu comentario, hay algunas soluciones. Supongo que quieres:

file1 1
      2
      3

etc. Simplemente suelte echoy modifique la línea 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

Dejé awkhacer la impresión por mí. Usar -vme permite pasar una variable en f. Para la impresión, familiarícese con printfla sintaxis (puede usarla man printfen el shell. Básicamente, estoy asumiendo dos campos, uno con 20, el otro con 5 y un espacio entre ellos. El signo negativo justifica a la izquierda. Puedes jugar con él. Esto He solucionado su problema inicial, ya que ahora puede canalizar esa única línea.

Si desea que el archivo sea simplemente:

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

puede eliminarlo ifen mi awkdeclaración o dejar la solución inicial con eco, pero use,

echo -n "$file,"

donde -ngarantiza que no se imprima ninguna nueva línea.

información relacionada