2016-07-16 47 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和條件表達式。