2016-07-16 39 views
1

将文本文件读入数组中,提取元素并对它们进行排序需要很长时间。从数组中排序字符串需要很长时间

该文本文件是用于R128音频分析的ffmpeg控制台输出。我需要获得最高的M和S值。例如:

[Parsed_ebur128_0 @ 0x7fd32a60caa0] t: 4.49998 M: -22.2 S: -29.9  I: -27.0 LUFS  LRA: 9.8 LU FTPK: -12.4 dBFS TPK: -9.7 dBFS 
[Parsed_ebur128_0 @ 0x7fd32a60caa0] t: 4.69998 M: -22.5 S: -28.6  I: -25.9 LUFS  LRA: 11.3 LU FTPK: -12.7 dBFS TPK: -9.7 dBFS 

文本文件可以是几百或几千个长视音频文件的时间线中的分析
我想找到的最高M(-22.2)和S值(-28.6)并将其分配给变量M和S

这是我在用目前:

ARRAY=() 
while read LINE 
do 
ARRAY+=("$LINE") 
done < $tempDir/text.txt 

for LINE in "${ARRAY[@]}" 
do 
echo "$LINE" | sed -n ‘/B:/p' | sed 's/S:.*//' | sed -n -e 's/^.*M://p' | sed -n -e 's/-//p' >>/$tempDir/R128M.txt 
done 
for LINE in "${ARRAY[@]}" 
do 
echo "$LINE" | sed -n '/M:/p' | sed 's/I:.*//' | sed -n -e 's/^.*S://p' | sed -n -e 's/-//p' >>$tempDir/R128S.txt 
done 

cat $tempDir/R128M.txt 
M=($(sort $tempDir/R128M.txt)) 

cat $tempDir/R128S.txt 
S=($(sort $tempDir/R128S.txt)) 

是否有这样做的一个更快的方法?

+1

是的。人们通常不会选择用bash脚本来写速度。即使是一个合适的perl脚本也可能在这里给你一个数量级的速度提升,尤其是看到它主要是正则表达式处理。 – davmac

回答

2

而不是读整个文件在内存中,写的是位出单独的文件,并重新读取这些,只需分析它,并挑选出最大的价值:

$ awk '$7 > m || m == "" { m = $7 } $9 > s || s == "" { s = $9 } END { print m, s }' data 
-22.2 -28.6 

在你的数据,字段7和9包含M和S的值。awk脚本将更新其ms变量,前提是它在这些字段中找到较大的值,然后打印最后找到的最大值。如果尚未读取任何值,则需要m == ""s == ""来触发值的初始化。

另一种方式与awk,这可能看起来更干净:

$ awk 'FNR == 1 { m = $7; s = $9; next } $7 > m { m = $7 } $9 > s { s = $9 } END { print m, s }' data 

将它们分配给MS在shell:

$ declare $(awk 'FNR == 1 { m = $7; s = $9; next } $7 > m { m = $7 } $9 > s { s = $9 } END { printf("M=%f S=%f\n", m, s) }' data) 

$ echo $M $S 
-22.200000 -28.600000 

调整printf()格式使用%s代替%f如果您需要原始字符串而不是浮点值,或者设置您可能需要的小数位数,例如,%.2f就位%f

+0

谢谢 - 这工作完美。感谢您将额外的信息也分配到脚本中。 – ssmc

1

首先,对于单个数值提取,三进程管道有点多余,特别是考虑到您重新为每个一行重新实例化了一次

接下来,将所有值保存到一个文件中,然后对该文件进行排序,而所需的只是最大值。您可以在第一个(值提取)循环中轻松找到它,以获得额外的O(N)运行时间,而不是I/O,并对所有I/O开销和O(NlogN)排序开销进行排序。请参阅bash手册中的ARITHMETIC EXPANSION和条件表达式。