Як можна підсумовувати числа по рядках у файлі


24

У мене є файл, який виглядає приблизно так:

1
3
4
1
4
3
1
2

Як я можу знайти загальну суму цього (тобто 1 + 3 + 4 + 1 + 4 + 3 + 1 + 2 = 19)?


1
У контексті я підраховую кількість значків, які я маю на Ask Ubuntu від API стека Exchange.
Тім

Зcat badges.json | grep -o '"award_count":[0-9],"rank":"gold"' | grep -o [0-9]
Тім

Хоча зараз я розумію, що в API є badge_countметод.
Тім

Якщо ви рахуєте значки з API, мова, якою ви користуєтесь для запиту API, не може цього зробити (python, javascript)?
Брайам

Відповіді:


42

bcза допомогою невеликої допомоги, pasteщоб отримати рядки в єдиній з +роздільником:

paste -sd+ file.txt | bc

Щоб використовувати висновок grep(або будь-яку іншу команду) замість статичного файлу, передайте grepSTDOUT 's в STDIN paste:

grep .... | paste -sd+ | bc

Приклад:

% cat file.txt            
1
3
4
1
4
3
1
2

% paste -sd+ file.txt | bc
19

% grep . file.txt | paste -sd+ | bc
19

Якщо потрібно використовувати bash, то ви можете використовувати масив для збереження вмісту файлу, а потім перебирати елементи або ви можете читати файл за рядком і робити суму для кожного рядка, другий підхід був би більш ефективним:

$ time { nums=$(<file.txt); for i in ${nums[@]}; do (( sum+=i )); done; echo $sum ;}
19

real    0m0.002s
user    0m0.000s
sys 0m0.000s

$ time { while read i; do (( sum+=i )); done <file.txt; echo $sum ;}
19

real    0m0.000s
user    0m0.000s
sys 0m0.000s

Хм, приємно. Вибачте, що змінили питання: чи можу я змінити це, щоб прийняти греп-вихід (або зробити його таким, як cat file.txt | bc?
Тім

@Tim Перевір мої зміни
heemayl

Та, це було просто!
Тім

2
Стродий спосіб не працював для мене, поки я не виявив в іншій відповіді, що мені довелося використовувати paste -sd+ -. Будь ласка, виправте це.
Ксерус

19

Ви можете також використовувати awk. Для підрахунку загальної кількості рядків у файлах * .txt, що містять слово "привіт":

grep -ch 'hello' *.txt | awk '{n += $1}; END{print n}'

Щоб просто підсумувати числа у файлі:

awk '{n += $1}; END{print n}' file.txt

Але якщо цей рядок має значення "4", він не буде рахувати 4, це буде. Він буде рахувати 1.
Тім

Ні, це буде рахувати 4.
CrazyApe84

Я хочу загальну кількість у файлі. Це робить це?
Тім

Я думав, ти змінив своє питання на вихід grep. Я робив певні припущення. Я додам, як просто підсумовувати значення у файлі.
CrazyApe84

2
Так. Це дійсно та сама відповідь, що і heemayl's, але замість пасти та bc вона використовує awk, що в кінцевому підсумку дає набагато більше гнучкості. Тим не менш, його відповідь хороша, і він був першим, тому він заслуговує на ваш голос!
CrazyApe84

7

Використовуйте numsumз упаковки num-utils!

(Можливо, вам доведеться sudo apt-get install num-utils)

Команда numsumвиконує лише те, що вам потрібно за замовчуванням;

$ numsum file.txt 
19

Читання тестових чисел по рядках з stdin:

$ printf '
1 
3
4
1
4
3
1
2' | numsum
19

Або читання з одного рядка:

$ printf '1 3 4 1 4 3 1 2' | numsum -r
19


Більше комунальних послуг

Пакет містить деякі інші утиліти для обробки номерів, які заслуговують на те, щоб бути більш відомими:

numaverage   - find the average of the numbers, or the mode or median
numbound     - find minimum of maximum of all lines
numgrep      - to find numbers matching ranges or sets
numinterval  - roughly like the first derivative
numnormalize - normalize numbers to an interval, like 0-1
numrandom    - random numbers from ranges or sets, eg odd.  
numrange     - similar to seq
numround     - round numbers up, down or to nearest

і більш загальну команду калькулятора numprocess,
яка застосовує вираз із командного рядка до чисел у рядках введення.


1

Ви можете використовувати awkнативну програму Linux, яка корисна для сканування та обробки файлів з малюнком на рядок. Що стосується вашого питання, це призведе до того, що ви хочете:

awk 'BEGIN { sum=0 } { sum+=$1 } END {print sum }' file.txt

Труби також приймають:

cat file.txt | awk 'BEGIN { sum=0 } { sum+=$1 } END {print sum }'

BEGIN{}Блоку не потрібно , дивіться відповідь CrazyApe84 .
тердон

Ця проблема є зайвою, але я вважаю за краще включити її через дидактичну мету.
гвара

Але чого це вчить? Це зайве для кожної проблеми, awkце не C, вам не потрібно встановлювати змінну перед її використанням. Спробуйте awk 'BEGIN{print c+=1}'.
тердон

BEGIN {}Блок не був розроблений просто для ініціалізації змінних. Він бере участь у специфікації дизайну. Отже, з деяких проблем це може знадобитися.
гвара

0

Це досить просте використання bashсценаріїв.

SUM=0; for line in `cat file.txt`; do SUM=$((SUM + line)); done

Це набагато простіше і набір інструментів мінімалістичний, ніж поточне рішення.
Дет

0

Розчин Perl:

$ perl -lnae '$c+=$_;END{print $c}' input.txt                                                                            
19

Вищезазначене може підсумовувати всі числа в кількох файлах:

$ perl -lnae '$c+=$_;END{print $c}' input.txt input2.txt                                                                 
34

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

$ perl -lnae '$c+=$_;if(eof){printf("%d %s\n",$c,$ARGV);$c=0}' input.txt input2.txt                                      
19 input.txt
15 input2.txt


0

Простий підхід полягає у використанні вбудованої функції вашої оболонки:

SUM=0; while read N; do SUM=$((SUM+N)); done </path/to/file
echo $SUM

Це читає ваш файл лінійно, підбиває підсумки та друкує результат.

Якщо ви хочете використовувати трубу і використовувати лише 1-й ряд, це працює так:

SUM=0
your_command | while read -r LINE; do for N in $LINE; do break; done; SUM=$((SUM+N)); done
echo $SUM

Отримання першого елемента робиться так:

LIST="foo bar baz"
for OBJ in $LIST; do break; done
echo $OBJ

foo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.