Як я можу швидко підсумовувати всі числа у файлі?


16

Кожен рядок містить текст і цифри в одному стовпчику. Мені потрібно обчислити суму чисел у кожному рядку. Як я можу це зробити? Дякую

example.log містить:

time=31sec
time=192sec
time=18sec
time=543sec

Відповідь має бути 784


Я спробував цей метод awk '{sum + = $ 1}; КІНЦЕ {print sum} 'example.log, але це лише для рядків під номером
Джек

2
Є майже те саме питання у " Переповнення стека" : Як я можу швидко підсумовувати всі числа у файлі? . Можливо, час мати копії між сайтами?
fedorqui

Відповіді:


18

Якщо ваш варіант grepпідтримки -o, ви можете спробувати:

$ grep -o '[[:digit:]]*' file | paste -sd+ - | bc
784

POSIXly:

$ printf %d\\n "$(( $(tr -cs 0-9 '[\n*]' <file | paste -sd+ -) ))"
784

16

З новою версією (4.x) GNU awk:

awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}'

За допомогою іншого awkспробуйте:

awk -F '[a-z=]*' '{s+=$2}END{print s}'

4
Вам потрібно s+0у випадку, коли sпорожній, він буде надруковано 0замість порожнього.
cuonglm

Дозвольте мені пояснити це. - Є лише один випадок, коли sможна пустувати; якщо вхідні дані не містять рядків (тобто якщо взагалі немає введення ). У такому випадку можливі дві поведінки; 1) немає вводу => немає виводу, або 2) завжди щось виводить, якщо тільки 0. Обидва є розумними варіантами залежно від контексту програми. Варіант +0адресації 2). Щоб вирішити варіант 1), вам доведеться написати END {if(s) print s}. - Тому не має сенсу припускати будь-який варіант (для цього кутового випадку відсутні дані), поки він не буде визначений питанням.
Яніс

10
awk -F= '{sum+=$2};END{print sum}'

2
Ми віддаємо перевагу довгі форми відповідей. Чи можете ви, будь ласка, детальніше розповісти, як це працює?
slm

2
@slm, ця відповідь не є більш-менш багатослівною, ніж інші відповіді тут, і сама пояснює. Вона також має перевагу роботи з вхідним сигналом , якtime=1.4e5sec
Stéphane Chazelas

@ StéphaneChazelas - погодився, але це новий користувач, і ми радимо користувачам надати більше, ніж відповіді на один рядок. Трохи тексту, що пояснює, як це працює, зробить це набагато сильнішою відповіддю, ніж просто код.
slm

4
@slm, це новий користувач з однією з найкращих відповідей (з технічної точки зору), і він отримує два рейтинги та негативний коментар. Не дуже теплий прийом.
Стефан Шазелас

1
@TomFenech, синтаксис POSIX для awk вимагає, щоб ці елементи шаблону / дії були розділені або ";" або "новий рядок", тож ви можете знайти дивовижні реалізації там, де це не вдається без цього ";".
Стефан Шазелас

7

Ще один GNU awk:

awk -v RS='[0-9]+' '{n+=RT};END{print n}'

Один perl:

perl -lne'$n+=$_ for/\d+/g}{print$n'

POSIX один:

tr -cs 0-9 '[\n*]' | grep . | paste -sd + - | bc

6
sed 's/=/ /' file | awk '{ sum+=$2 } END { print sum}'

sedawk --field-separator = '{ sum+=$2 } END { print sum}' data.dat
Чудова

@ user1717828: скоріше скористайтеся (коротше і сумісніше!) -F'='замість--field-separator =
Олів'є Дулак

@OlivierDulac, дивно, мій man awkтільки дає -F fsі--field-separator fs
користувач1717828

@ user1717828: -F'='або -F '='два способи зробити -F fs(у вашому випадку fs - "="). Я додав сингрети, щоб переконатися, що fs належним чином бачиться & інтерпретується awk, а не оболонкою (корисно, якщо fs ';', наприклад)
Олів'є Дулак


4

Усі опублікували дивовижні awk відповіді, які мені дуже подобаються.

Варіант @cuonglm замінюється grepна sed:

sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
  1. The sedСмуги все для чисел , за винятком.
  2. paste -sd+ -Команда об'єднує всі лінії разом в одному рядку
  3. bcобчислює вираз

3

Слід скористатися калькулятором.

{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null

Ваші чотири рядки, які друкують:

time=31
time=223
time=241
time=784

А простіше:

tr times=c '    + p' <infile |dc

... які друкує ...

31
223
241
784

Якщо швидкість - це те, що ви хочете, то dcте, що ви хочете. Традиційно це був bcкомпілятор - і досі є для багатьох систем.


Не за моїми вимірами : залежить, скільки роботи потрібно зробити, щоб сформувати формулу
Гленн Джекман

@glennjackman - ваші вимірювання не включають dcтак близько, як я можу сказати. Про що ти говориш?
mikeserv

До речі, при порівнянні старого екіпажу з новим екіпажем - наприклад, коли ви орієнтуєтесь perlна стандартний набір інструментів unix - це насправді не має особливого сенсу, якщо ви використовуєте інструменти GNU, зібрані на інструментальній ланцюзі GNU. Весь перебіг, який може негативно вплинути на продуктивність Perl, також є у всіх цих утилітах GNU, складених GNU. Сумно але правда. Вам потрібен справжній, просто побудований, простий набір інструментів, щоб точно оцінити різницю. Як, наприклад, набір інструментів для спадкоємців, статично пов'язаний з musl libs, - таким чином ви можете порівняти парадигму "один інструмент / одна робота" проти "єдиного інструмента для управління правилом".
mikeserv

3

Через python3,

import re
with open(file) as f:
    m = f.read()
    l = re.findall(r'\d+', m)
    print(sum(map(int, l)))

re.findallповертає список рядків, це не буде працювати
iruvar

@ 1_CR ya, я це забуваю. Перевірте це зараз.
Авінаш Радж

Можливо, sum(int(e) for e in l)є більш пітонічним.
cuonglm

3

Чистий розчин башу (Bash 3+):

while IFS= read -r line; do                   # While it reads a line:
    if [[ "$line" =~ [0-9]+ ]]; then      # If the line contains numbers:
        ((counter+=BASH_REMATCH[0]))          # Add the current number to counter
    fi                                    # End if.
done                                  # End loop.

echo "Total number: $counter"         # Print the number.
unset counter                         # Reset counter to 0.

Коротка версія:

while IFS= read -r l; do [[ "$l" =~ [0-9]+ ]] && ((c+=BASH_REMATCH)); done; echo $c; c=0

1
Можливо також:PS4='$((x+=${time%s*}))' time=0 x=0 sh -x <infile
mikeserv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.