Durchlaufen Sie das Verzeichnis und summieren Sie den Wert neben einem bestimmten Muster, um einen Durchschnitt zu erhalten.

Durchlaufen Sie das Verzeichnis und summieren Sie den Wert neben einem bestimmten Muster, um einen Durchschnitt zu erhalten.

Ich möchte alle Dateien im Verzeichnis durchlaufen.

Die Dateien sind wie folgt angeordnet:

<Overall>4
other data
<Overall>2
other data
......

Ich habe den Code:

for file in .dat; 
do
awk 'x+=sub(/<Overall>/,""){y+=$0} END{print FILENAME, y/x}' $file
done

Dadurch wird der Durchschnitt der Werte in der Datei ausgedruckt. Ich möchte jedoch das Verzeichnis, in dem sich mein Skript befindet, als Argument nehmen und den awk-Befehl für alle .dat-Dateien im Verzeichnis ausführen.

Ich habe versucht, den Code zu verwenden:

for file in $1

aber bekomme den Fehler:

awk: cmd. line:1: fatal cannot open file `folder' for reading (No such file or directory)

Darüber hinaus möchte ich die Ausgabe der Durchschnittswerte von hoch nach niedrig sortieren können.

Antwort1

Zwei Varianten:

  1. Führen Sie eine Schleife über die Dateien aus und rufen Sie den Vorgang awkeinmal für jede Datei auf, oder
  2. Geben Sie dem awkSkript alle Dateien, lassen Sie es für jede Datei den Durchschnitt berechnen und im Verlauf einen Bericht erstellen.

Das Sortieren der Ergebnisse der folgenden Lösungen kann durch Weiterleiten der Ergebnisse über

sort -k2,2rn

Dadurch wird eine umgekehrte numerische Sortierung des zweiten Felds (der Durchschnittswerte) durchgeführt.


Erste Lösung:

#!/bin/sh

for name in "$1"/*.dat; do
    test -f "$name" || continue   # skip non-files
    awk -F '>' '/<Overall>/ { s+=$NF; n++ } END { print FILENAME, s/n }' "$name"
done

Dieses Skript erwartet einen Verzeichnisnamen in der Befehlszeile als erstes und einziges Befehlszeilenargument. Das awkSkript findet alle Zeilen, die die Zeichenfolge enthalten Overall, und summiert (in s) den Wert nach dem >in dieser Zeile. Am Ende wird der Durchschnitt zusammen mit dem Dateinamen ausgegeben. Die Variable nenthält die Anzahl, wie oft wir etwas zu hinzugefügt haben s.


Zweite Lösung (erfordert GNU Awk):

#!/bin/sh

find "$1" -maxdepth 1 -type f -name '*.dat' \
    -exec awk -F '>' '/<Overall>/ { s+=$NF; n++ } ENDFILE { print FILENAME, s/n; s=n=0 }' {} +

Dieses Skript erwartet wie das erste als einziges Befehlszeilenargument einen Verzeichnisnamen. Es dient finddazu, ein awkSkript mit so vielen .datDateien wie möglich gleichzeitig auszuführen.

Das awkSkript verwendet den ENDFILETrigger von GNU Awk, um die berechneten Werte auszugeben und die Variablen nach der Verarbeitung jeder Datei zurückzusetzen s, nbevor mit dem Lesen der nächsten Datei begonnen wird.

Dies könnte auch geschrieben worden sein als

#!/bin/sh

awk -F '>' '/<Overall>/ { s+=$NF; n++ } ENDFILE { print FILENAME, s/n; s=n=0 }' "$1"/*.dat

Dies setzt jedoch voraus, "$1"/*.datdass die Liste der Dateinamen nicht zu lang wird (dies erfordert außerdem, .datdass jeder Name eine reguläre Datei ist, was durch den obigen findBefehl mit garantiert wird -type f).

verwandte Informationen