Verwenden von grep, awk und csv zum Extrahieren von Informationen aus Textdateien

Verwenden von grep, awk und csv zum Extrahieren von Informationen aus Textdateien

Ich verwende den folgenden Code, um Informationen aus einer Reihe von Textdateien (foo*.txt) zu extrahieren.

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

Dieser Kommentar druckt die gewünschten Zahlen aus einer Reihe von Dateien (foo*.txt). Wenn ich versuche, sowohl den Dateinamen (in einer Spalte der CSV-Datei) als auch die Nummer (in der nächsten Spalte der CSV-Datei) auszudrucken, habe ich Folgendes im Terminal versucht.

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

Dadurch werden die Namen der Dateien auf dem Terminal ausgedruckt. Die CSV-Datei enthält die gewünschten Zahlen. Wie kann dieser Code geändert werden, sodass der Name der Datei in einer Spalte und die extrahierten Zahlen in der nächsten Spalte der CSV-Datei ausgedruckt werden?

Ein weiteres Problem in diesem Code ist das Sortierproblem. Betrachten Sie beispielsweise die Dateinamen foo_01_s.txt, foo_02_s.txt, foo_03_s.txt...foo_100_s.txt. Wenn ich Informationen extrahieren möchte (unter Verwendung der obigen Kommentare), kommt die letzte Datei (foo_100_s.txt) nicht nach foo_99_s.txt.

Eine Lösung mit Python/Perl wäre auch hilfreich.

Antwort1

Sie müssen verstehen, dass Ihr >>nur den Teil des aktuellen Befehls umleitet – im Grunde nur die Zahl, die das Ergebnis des Befehls ist grep, der mit beginnt und ein paar Mal weitergeleitet wird. echo $fileist ein separater Befehl (Sie verwenden ;) und leitet daher normalerweise zu stdout weiter. Sie müssen nur nach der gesamten Schleife umleiten:

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

Wenn Sie Ihre Dateien nach „Versionen“ sortieren möchten (das ist ein passender Name), können Sie sie nach der Sortierung auflisten:

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

um schnell etwas Kleines auszuführen (einige Minuten für ~1000 Dateien), sollte das ausreichen.

BEARBEITEN

Nach Ihrem Kommentar gibt es einige Lösungen. Ich vermute, Sie möchten:

file1 1
      2
      3

usw. Lassen Sie einfach das weg echound ändern Sie die Echozeile:

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

Ich lasse awkdas Drucken für mich erledigen. Die Verwendung -vermöglicht es mir, eine Variable in zu übergeben f. Machen Sie sich für das Drucken mit printfder Syntax vertraut (Sie können man printfin der Shell verwenden). Grundsätzlich gehe ich von zwei Feldern aus, eines mit 20, das andere mit 5 und einem Leerzeichen dazwischen. Das Minuszeichen richtet linksbündig aus. Sie können damit herumspielen. Dies hätte Ihr ursprüngliches Problem behoben, da Sie jetzt diese einzelne Zeile weiterleiten können.

Wenn Sie möchten, dass die Datei nur Folgendes enthält:

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

Sie können entweder das ifin meiner awkAnweisung weglassen oder die ursprüngliche Lösung mit Echo belassen, aber verwenden,

echo -n "$file,"

wobei -nsichergestellt wird, dass keine neue Zeile gedruckt wird.

verwandte Informationen