![高效解析海量文件](https://linux22.com/image/210877/%E9%AB%98%E6%95%88%E8%A7%A3%E6%9E%90%E6%B5%B7%E9%87%8F%E6%96%87%E4%BB%B6.png)
我有一个包含数十万个文件的文件夹,名为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