Пройдитесь по каталогу и просуммируйте значение рядом с определенным шаблоном, получив среднее значение

Пройдитесь по каталогу и просуммируйте значение рядом с определенным шаблоном, получив среднее значение

Я хочу перебрать все файлы в каталоге.

файлы расположены следующим образом:

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

У меня есть код:

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

это выводит среднее значение значений в файле, однако мне нужно взять каталог, в котором находится мой скрипт, в качестве аргумента и выполнить команду awk для всех файлов .dat в этом каталоге.

Я попробовал использовать код:

for file in $1

но получаю ошибку:

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

В дополнение к этому я также хочу иметь возможность сортировать вывод средних значений от большего к меньшему.

решение1

Два варианта:

  1. Перебрать все файлы и вызвать awkодин раз для каждого файла, или
  2. Предоставьте awkскрипту все файлы и позвольте ему вычислить среднее значение для каждого из них и выдать отчет по мере выполнения.

Сортировка результата любого из приведенных ниже решений может быть выполнена путем передачи их вывода через

sort -k2,2rn

Это выполняет обратную числовую сортировку по второму полю (средние значения).


Первое решение:

#!/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

Этот скрипт ожидает имя каталога в командной строке в качестве первого и единственного аргумента командной строки. Скрипт awkнайдет все строки, содержащие строку Overall, и просуммирует (в s) значение после >в этой строке. В конце выводится среднее значение вместе с именем файла. Переменная nсодержит количество раз, когда мы что-то добавляли к s.


Второе решение (требуется 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 }' {} +

Этот скрипт, как и первый, ожидает имя каталога в качестве единственного аргумента командной строки. Он используется findдля выполнения awkскрипта с максимально .datвозможным количеством файлов одновременно.

Скрипт awkиспользует ENDFILEтриггер GNU Awk для вывода вычисленных значений и сброса переменных sи nпосле обработки каждого файла, перед началом чтения следующего файла.

Это также могло быть написано как

#!/bin/sh

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

но это не позволяет "$1"/*.datрасширить список имен файлов до слишком длинного (это также требует, чтобы каждое .datимя было обычным файлом, что findгарантирует приведенная выше команда с помощью -type f).

Связанный контент