循环遍历特定模式旁边的目录和总和值,生成平均值

循环遍历特定模式旁边的目录和总和值,生成平均值

我想循环遍历目录中的所有文件。

文件的设置如下:

<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

这会打印出文件中值的平均值,但是我想要的是将脚本所在的目录作为参数,并对目录中的所有 .dat 文件执行 awk 命令。

我尝试过使用代码:

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>ns


第二种解决方案(需要 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脚本利用 GNU Awk 的ENDFILE触发器来输出计算值,并在处理每个文件后、开始读取下一个文件之前重置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)。

相关内容