Как вычислить среднее из данных файла 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 ответов

Другой способ, используя sed и bc:

sed 's/^/n+=1;x+=/;$ascale=1;x/n' timemeasurements.txt | bc

Команда sed преобразует вход в нечто подобное:

n+=1;x+=2.5
n+=1;x+=3.5
n+=1;x+=2.0
scale=1;x/n

bc, который оценивает его по очереди.

11
ответ дан 22 May 2018 в 23:58

Другой способ, используя sed и bc:

sed 's/^/n+=1;x+=/;$ascale=1;x/n' timemeasurements.txt | bc

Команда sed преобразует вход в нечто подобное:

n+=1;x+=2.5 n+=1;x+=3.5 n+=1;x+=2.0 scale=1;x/n

bc, который оценивает его по очереди.

11
ответ дан 18 July 2018 в 15:30

Другой способ, используя sed и bc:

sed 's/^/n+=1;x+=/;$ascale=1;x/n' timemeasurements.txt | bc

Команда sed преобразует вход в нечто подобное:

n+=1;x+=2.5 n+=1;x+=3.5 n+=1;x+=2.0 scale=1;x/n

bc, который оценивает его по очереди.

11
ответ дан 24 July 2018 в 20:39

Другой способ, используя sed и bc:

sed 's/^/n+=1;x+=/;$ascale=1;x/n' timemeasurements.txt | bc

Команда sed преобразует вход в нечто подобное:

n+=1;x+=2.5 n+=1;x+=3.5 n+=1;x+=2.0 scale=1;x/n

bc, который оценивает его по очереди.

11
ответ дан 31 July 2018 в 11:10

Другой способ, используя sed и bc:

sed 's/^/n+=1;x+=/;$ascale=1;x/n' timemeasurements.txt | bc

Команда sed преобразует вход в нечто подобное:

n+=1;x+=2.5 n+=1;x+=3.5 n+=1;x+=2.0 scale=1;x/n

bc, который оценивает его по очереди.

11
ответ дан 31 July 2018 в 12:08

Другой способ, используя sed и bc:

sed 's/^/n+=1;x+=/;$ascale=1;x/n' timemeasurements.txt | bc

Команда sed преобразует вход в нечто подобное:

n+=1;x+=2.5 n+=1;x+=3.5 n+=1;x+=2.0 scale=1;x/n

bc, который оценивает его по очереди.

11
ответ дан 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
ответ дан 22 May 2018 в 23:58
  • 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
ответ дан 22 May 2018 в 23:58
  • 1
    Хотя это хорошая практика, переменные на самом деле нуждаются для инициализации в awk - так что вы можете " гольф " это к awk '{total+=$1} END{print total/NR}' – steeldriver 5 April 2017 в 15:33
  • 2
    @steeldriver спасибо! Просто начинаю учиться :) – Zanna 5 April 2017 в 15:38

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

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

Вы можете использовать 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
ответ дан 22 May 2018 в 23:58

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

$ 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
ответ дан 22 May 2018 в 23:58

Вы можете использовать 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
ответ дан 18 July 2018 в 15:30

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

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

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

$ 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
ответ дан 18 July 2018 в 15:30

Обязательная версия 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
ответ дан 18 July 2018 в 15:30

Вы можете использовать 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
ответ дан 18 July 2018 в 15:30

Вы можете использовать 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
ответ дан 24 July 2018 в 20:39

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

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

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

$ 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
ответ дан 24 July 2018 в 20:39

Обязательная версия 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
ответ дан 24 July 2018 в 20:39
  • 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
ответ дан 24 July 2018 в 20:39
  • 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 в 11:10

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

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

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

$ 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 в 11:10

Обязательная версия 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 в 11:10
  • 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 в 11:10
  • 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 в 12:08

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

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

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

$ 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 в 12:08

Обязательная версия 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 в 12:08
  • 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

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

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