高效解析海量文件

高效解析海量文件

我有一个包含数十万个文件的文件夹,名为hp-temps.txt. (还有大量的子文件夹)

这些文件的内容如下所示:

Sensor   Location              Temp       Threshold
------   --------              ----       ---------
#1        PROCESSOR_ZONE       15C/59F    62C/143F 
#2        CPU#1                10C/50F    73C/163F 
#3        I/O_ZONE             25C/77F    68C/154F 
#4        CPU#2                32C/89F    73C/163F 
#5        POWER_SUPPLY_BAY     9C/48F     55C/131F 

我需要解析所有文件并在 #1 行中找到温度的最高条目。

我有一个工作脚本,但需要很长时间,我想知道是否有任何方法可以改进它。

由于我对 Shell 脚本相当陌生,我想我的这段代码效率确实很低:

#!/bin/bash
highesetTemp=0
temps=$(find $1 -name hp-temps.txt -exec cat {} + | grep 'PROCESSOR' | cut -c 32-33)
for t in $temps
do
  if [ $t -gt $highestTemp ]; then
    highestTemp=$t
  fi
done

编辑:

有一个非常有效的代码,但我忘了提及,我不仅需要最大的值。

我希望能够循环遍历所有文件,因为我希望在检测到更高值时输出文件的目录和温度。

因此,输出可能如下所示:

New MAX: 22 in /path/to/file/hp-temps.txt
New MAX: 24 in /another/path/hp-temps.txt
New MAX: 29 in /some/more/path/hp-temps.txt

答案1

将中间数据存储在字符串中会很慢,而且很少需要。在一般情况下,将多个字符串存储在单个标量变量中还有一个额外的问题,就像这样,每个子字符串可能包含空格或其他字符,稍后您可以通过在循环中使用不带引号的方式强制 shell 分割字符串for(它使用数组会更好)。

在这种情况下,查找每个文件、提取温度并读取该温度流会更有效。它还可以避免创建其中包含 300 KB(或更多)字符串的 shell 变量。

您可以从以下位置解析出摄氏温度文件使用

awk '$2 == "PROCESSOR_ZONE" { printf "%d\n", $3 }' file

当第二个字段恰好是字符串时,它输出第三个字段的温度PROCESSOR_ZONE。由于我们在写入时将第三个字段转换为整数,因此只会输出该值的第一部分(直到第一个非数字)。

从以下位置调用find

find . -name hp-temps.txt \
    -exec awk '$2 == "PROCESSOR_ZONE" { printf "%d\n", $3 }' {} +

awk会对一批或多批找到的文件执行命令,并在标准输出上一个接一个地输出温度。

如果您使用的awk可以理解非标准nextfile语句,那么您可以使用它来尽快跳到下一个文件:

find . -name hp-temps.txt \
    -exec awk '$2 == "PROCESSOR_ZONE" { printf "%d\n", $3; nextfile }' {} +

为了找到上述命令输出的最大值,我们还可以使用一个awk命令:

awk 'NR == 1 || $1 > max { max = $1 } END { print max }'

awk如果变量的值max是迄今为止看到的第一个或最大值,则将变量的值设置为当前输入值。最后max输出 的值。

我希望这比 shell 循环快很多倍。

将其放在一起:

find . -name hp-temps.txt \
    -exec awk '$2 == "PROCESSOR_ZONE" { printf "%d\n", $3; nextfile }' {} + |
awk 'NR == 1 || $1 > max { max = $1 } END { print max }'

还有一个额外的请求,要求找出具有最大值的文件的文件名。我们只需传递文件名以及每个文件的值即可做到这一点。在 中awk,当前输入文件的路径名可用作特殊变量FILENAME

find . -name hp-temps.txt \
    -exec awk '$2 == "PROCESSOR_ZONE" { printf "%d\t%s\n", $3, FILENAME; nextfile }' {} + |
awk 'NR == 1 || $1 > max { max = $1; fname = $2 } END { print max, fname }'

如果多个文件具有相同的最大值,则会报告 找到的第一个文件的文件名find。该实用程序以与列出文件find相同的顺序查找文件。ls -f

相关内容