2016-07-16 2 views
1

Чтение текстового файла в массив, извлечение элементов и их сортировка занимают очень много времени.Сортировка строк из массива занимает много времени

Текстовый файл представляет собой вывод консоли ffmpeg для анализа звука R128. Мне нужно получить наивысшие значения 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 обновит свои переменные m и s, если он найдет большие значения в этих полях и затем распечатает наибольшее найденное в конце. m == "" и s == "" необходимы для инициализации значений, если значения еще не были прочитаны.

Другой способ с awk, который может выглядеть чище:

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

Чтобы назначить их M и S в оболочке:

$ 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 если вам нужны исходные строки вместо значений float или задайте количество десятичных знаков, которое вы, возможно, захотите, например, %.2f на месте от %f.

+0

Спасибо - это сработало отлично. Признайте, что вы добавили дополнительную информацию и в сценарий. – ssmc

1

Прежде всего, трехпроводная труба немного избыточна для однократной экстракции, особенно с учетом того, что вы заново заново заново ее используете для каждую линию.

Затем вы сохраняете все значения в файле, а затем сортируете этот файл, а все, что вам нужно, - это максимальное значение. Вы можете легко найти его в течение самого первого цикла извлечения извлечения (value extract), для дополнительного времени работы O(N), вместо ввода-вывода и сортировки со всеми расходами на ввод-вывод и O(NlogN). См. ARITHMETIC EXPANSION и условные выражения в руководстве bash.

Смежные вопросы