Как вычислить среднее из данных файла ASCII в bash?

В bash я могу выполнить некоторые измерения времени из файла журнала, подобного этому

grep "time:" myLogfile.txt | cut -d' ' -f 3 >> timeMeasurements.txt #timeMeasurements.txt 2.5 3.5 2.0 ...

Теперь я хотел бы вычислить среднее значение из значений в timeMeasurements.txt. Каков самый быстрый способ сделать это в bash? Я знаю, что есть gnuplot и R, но кажется, что нужно написать длинный скрипт для одного из них.

7
задан 6 April 2017 в 05:41

40 ответов

Вы можете использовать awk. Bash сам по себе не очень хорош в математике ...

awk 'BEGIN { lines=0; total=0 } { lines++; total+=$1 } END { print total/lines }' timeMeasurements.txt

Примечания

lines=0; total=0 задают переменные до 0 lines++ увеличивают lines на 1 для каждой строки total+=$1 добавьте значение в каждой строке в текущую итоговую print total/lines, когда закончите, разделите общее число на число значений
12
ответ дан 31 July 2018 в 12:08
  • 1
    Хотя это хорошая практика, переменные на самом деле нуждаются для инициализации в awk - так что вы можете & quot; гольф & quot; это к awk '{total+=$1} END{print total/NR}' – steeldriver 5 April 2017 в 15:33
  • 2
    @steeldriver спасибо! Просто начинаю учиться :) – Zanna 5 April 2017 в 15:38

Вы можете использовать bc базовый калькулятор в цикле while с read:

count=0; sum=0; while read -r num; do ((count++)); sum=$(echo "$sum + $num" | bc); done < timeMeasurement.txt; echo "scale=2; $sum / $count" | bc -l

Или более читаемо:

count=0 sum=0 while read -r num do ((count++)) sum=$(echo "$sum + $num" | bc) done < timeMeasurement.txt echo "scale=2; $sum / $count" | bc -l

Объяснение:

Сначала мы устанавливаем счетчик значений и сумму в виде количества и суммы переменных со значениями 0. Прочитайте файл по строкам, установив значение в строке как переменную num. Для этого мы используем конструкцию while read -r num; do ... ; done < timeMeasurements.txt. Это будет означать, что мы сделаем что-то для каждой строки файла. Внутри цикла while добавьте переменную count по одной для каждой строки с арифметикой bash ((count++)). Используйте команду bash подстановки $(...) с echo, переданной по каналу bc, чтобы добавить значение переменной num для этой строки файла, к сумме переменной num из всех предыдущих строк. bc используется, поскольку bash не справляется с арифметикой с плавающей запятой.

В этот момент цикл заканчивается, переменная count содержит количество измеренных значений времени, переменная суммы содержит сумму измерений времени.

Сначала мы устанавливаем подсчет значений и сумма в виде числа и суммы переменных со значениями 0.
5
ответ дан 31 July 2018 в 23:40

Адаптация команды R из этого сообщения U & amp; L:

$ Rscript -e 'd<-scan("stdin", quiet=TRUE)' -e 'cat(mean(d), sep="\n")' < foo 2.666667
8
ответ дан 31 July 2018 в 23:40

Датамаш кажется хорошим вариантом, но даже признавая, что мой ответ может быть излишним, на всякий случай, если вы хотите сделать немного больше, чем просто среднее значение, октава не такая подробная:

$ octave octave:1> load timeMeasurements.txt octave:2> mean(timeMeasurements) ans = 2.6667

Если вы делаете это, помните, что одно и то же среднее может иметь разные типы поведения, поэтому стандартное отклонение обычно также имеет значение:

octave:3> std(timeMeasurements) ans = 0.76376

или даже простая гистограмма проста: [ ! d2] octave:4> hist(timeMeasurements)

Кроме того, я думаю, что datamash не находится в репозиториях apt-get для trusty, только для более новых версий.

Edit:

Oneliner, для более дружественные сценарии:

octave -q --eval "m = load(\"timeMeasurements.txt\"); mean(m)"
4
ответ дан 31 July 2018 в 23:40

Обязательная версия datamash GNU

$ datamash mean 1 < file 2.6666666666667

ASIDE: похоже, что это действительно должно быть возможно изначально в bc (т.е. без использования оболочки или внешней программы , для циклического ввода входных значений). Реализация GNU bc включает в себя функцию read() - однако, как представляется, сложно затруднить ее обнаружение конца ввода. Лучшее, что я мог бы придумать, это:

#!/usr/bin/bc scale = 6 while( (x = read()) ) { s += x c += 1 } s/c quit

, который затем вы можете подключить входной файл к ASIDE , например

$ { cat file; echo '@'; } | ./mean.bc 2.666666
13
ответ дан 31 July 2018 в 23:40
  • 1
    Не только кратчайший ответ, но и тем, кто интересуется статистикой, к удобной утилите +1 – WinEunuuchs2Unix 5 April 2017 в 15:44
  • 2
    Это выглядит интригующе коротко. Есть ли версия datamash для apt-get? – mcExchange 5 April 2017 в 22:57
  • 3
    @mcExchange sudo apt install datamash был достаточным для моей Ubuntu 16.04 VM. – Digital Trauma 6 April 2017 в 00:08
  • 4
    К сожалению, на Ubuntu 14.04 он не находится в репозиториях ... – mcExchange 6 April 2017 в 01:20

Вы можете использовать awk. Bash сам по себе не очень хорош в математике ...

awk 'BEGIN { lines=0; total=0 } { lines++; total+=$1 } END { print total/lines }' timeMeasurements.txt

Примечания

lines=0; total=0 задают переменные до 0 lines++ увеличивают lines на 1 для каждой строки total+=$1 добавьте значение в каждой строке в текущую итоговую print total/lines, когда закончите, разделите общее число на число значений
12
ответ дан 31 July 2018 в 23:40
  • 1
    Хотя это хорошая практика, переменные на самом деле нуждаются для инициализации в awk - так что вы можете & quot; гольф & quot; это к awk '{total+=$1} END{print total/NR}' – steeldriver 5 April 2017 в 15:33
  • 2
    @steeldriver спасибо! Просто начинаю учиться :) – Zanna 5 April 2017 в 15:38

Обязательно версия GNU datamash

$ datamash mean 1 < file
2.6666666666667

ASIDE: кажется, что действительно должно быть возможно изначально в bc (т.е. без использования оболочки или внешней программы для циклического ввода входных значений). Реализация GNU bc включает в себя функцию read() - однако, как представляется, сложно затруднить ее обнаружение конца ввода. Лучшее, что я мог бы придумать, это:

#!/usr/bin/bc

scale = 6
while( (x = read()) ) {
  s += x
  c += 1
}
s/c
quit

, который вы можете подключить к файлу, если вы завершаете ввод любым нечисловым символом, например

$ { cat file; echo '@'; } | ./mean.bc
2.666666
13
ответ дан 2 August 2018 в 18:37

Обязательно версия GNU datamash

$ datamash mean 1 < file
2.6666666666667

ASIDE: кажется, что действительно должно быть возможно изначально в bc (т.е. без использования оболочки или внешней программы для циклического ввода входных значений). Реализация GNU bc включает в себя функцию read() - однако, как представляется, сложно затруднить ее обнаружение конца ввода. Лучшее, что я мог бы придумать, это:

#!/usr/bin/bc

scale = 6
while( (x = read()) ) {
  s += x
  c += 1
}
s/c
quit

, который вы можете подключить к файлу, если вы завершаете ввод любым нечисловым символом, например

$ { cat file; echo '@'; } | ./mean.bc
2.666666
13
ответ дан 3 August 2018 в 20:56

Вы можете использовать awk. Bash сам по себе не очень хорош в математике ...

awk 'BEGIN { lines=0; total=0 } { lines++; total+=$1 } END { print total/lines }' timeMeasurements.txt

Примечания

  • lines=0; total=0 заданные переменные в 0
  • lines++ увеличиваются lines по одному для каждой строки
  • total+=$1 добавьте значение в каждой строке к текущему итогу
  • print total/lines, когда закончите, разделите общее число на количество значений
12
ответ дан 14 August 2018 в 21:26

Вы можете использовать bc базовый калькулятор в цикле while с read:

count=0; sum=0; while read -r num; do ((count++)); sum=$(echo "$sum + $num" | bc); done < timeMeasurement.txt; echo "scale=2; $sum / $count" | bc -l

Или более читаемо:

count=0
sum=0
while read -r num
do
  ((count++))
  sum=$(echo "$sum + $num" | bc)
done < timeMeasurement.txt
echo "scale=2; $sum / $count" | bc -l

Объяснение:

  • Сначала мы устанавливаем счетчик значений и сумму в виде числа и суммы переменных со значениями 0.
  • Прочитайте файл по строкам, установив значение в строке как переменной num. Для этого мы используем конструкцию while read -r num; do ... ; done < timeMeasurements.txt. Это будет означать, что мы сделаем что-то для каждой строки файла.
  • Внутри цикла while добавьте переменную count по одной для каждой строки с арифметикой bash ((count++)).
  • Использовать подстановку bash $(...) с echo с номером bc, чтобы добавить значение переменной num для этой строки файла, к сумме переменной num из всех предыдущих строк. bc используется, поскольку bash не справляется с арифметикой с плавающей запятой.

На этом этапе цикл заканчивается, переменная count содержит количество измеренных значений времени, переменная суммы содержит сумма временных измерений.

  • Используйте echo с нашими переменными, чтобы создать средний расчет, который передается на bc. Часть scale=2 сообщает bc, сколько значимых цифр будет отображаться.
5
ответ дан 14 August 2018 в 21:26

Другие вопросы по тегам:

Похожие вопросы: