Я хочу перебрать все файлы в каталоге.
файлы расположены следующим образом:
<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
Два варианта:
- Перебрать все файлы и вызвать
awk
один раз для каждого файла, или - Предоставьте
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
).