Команда оболочки для суммирования целых чисел, по одной в строке?

Я ищу команду, которая будет принимать в качестве ввода несколько строк текста, каждая строка содержит одно целое число и выводит сумму этих целых чисел.

В некотором смысле, у меня есть файл журнала, который включает в себя временные измерения, поэтому через grepping для соответствующих строк и немного переформатирования sed я могу перечислить все тайминги в этом файле. Однако я хотел бы выработать общий итог, и мой ум исчез, как к любой команде, я могу передать этот промежуточный вывод, чтобы сделать окончательную сумму. Я всегда использовал expr в прошлом, но если он не работает в RPN mode я не думаю, что он справится с этим (и даже тогда это будет сложно).

Что мне не хватает? Учитывая, что, возможно, есть несколько способов добиться этого, я буду рад прочитать (и upvote ) любой подход, который работает, даже если кто-то еще разместил другое решение, которое выполняет эту работу.

Связанный вопрос: Самая короткая команда для вычисления суммы столбца вывода на Unix? (кредиты @ Андрей )


Обновление : Вау, как и ожидалось, здесь есть хорошие ответы. Похоже, мне обязательно нужно будет дать awk более глубокое обследование в качестве command-line tool в целом!

Бит awk должен это сделать?

 awk '{s+=$1} END {print s}' mydatafile 

Примечание: некоторые версии awk имеют какое-то странное поведение, если вы собираетесь добавлять что-либо, превышающее 2 ^ 31 (2147483647). См. Комментарии для получения дополнительной информации. Одно предложение – использовать printf вместо print :

 awk '{s+=$1} END {printf "%.0f", s}' mydatafile 

Вставка обычно объединяет строки нескольких файлов, но также может использоваться для преобразования отдельных строк файла в одну строку. Флаг ограничителя позволяет передать уравнение типа x + x на bc.

 paste -s -d+ infile | bc 

Альтернативно, когда трубопроводы от stdin,

  | paste -s -d+ - | bc 

Версия с одним слоем в Python:

 $ python -c "import sys; print(sum(int(l) for l in sys.stdin))" 

Обычный баш:

 $ cat numbers.txt 1 2 3 4 5 6 7 8 9 10 $ sum=0; while read num; do ((sum += num)); done < numbers.txt; echo $sum 55 

Я бы поставил большое ПРЕДУПРЕЖДЕНИЕ на общепринятое решение:

 awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!! 

это потому, что в этой форме awk использует 32-битное целочисленное целое со знаком: оно будет переполняться для сумм, которые превышают 2147483647 (т. е. 2 ^ 31).

Более общий ответ (для суммирования целых чисел) будет:

 awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD 

PS Мне хотелось бы прокомментировать первый ответ, но у меня недостаточно репутации.

 dc -f infile -e '[+z1 

Обратите внимание, что отрицательные числа с префиксом минуса должны быть переведены для dc , поскольку для этого используется префикс _ а не префикс. Например, через tr '-' '_' | dc -f- -e '...' tr '-' '_' | dc -f- -e '...' .

Редактировать: Поскольку этот ответ получил так много голосов «за безвестность», вот подробное объяснение:

Выражение [+z1 делает следующее :

 [ interpret everything to the next ] as a string + push two values off the stack, add them and push the result z push the current stack depth 1 push one  

Как псевдокод:

  1. Определите «add_top_of_stack» как:
    1. Удалите два верхних значения из стека и добавьте результат назад
    2. Если стек имеет два или более значения, запустите «add_top_of_stack» рекурсивно
  2. Если стек имеет два или более значения, запустите «add_top_of_stack»,
  3. Распечатайте результат, теперь остается только один элемент в стеке

Чтобы действительно понять простоту и мощь dc , вот рабочий скрипт Python, который реализует некоторые команды из dc и выполняет версию Python указанной выше команды:

 ### Implement some commands from dc registers = {'r': None} stack = [] def add(): stack.append(stack.pop() + stack.pop()) def z(): stack.append(len(stack)) def less(reg): if stack.pop() < stack.pop(): registers[reg]() def store(reg): registers[reg] = stack.pop() def p(): print stack[-1] ### Python version of the dc command above # The equivalent to -f: read a file and push every line to the stack import fileinput for line in fileinput.input(): stack.append(int(line.strip())) def cmd(): add() z() stack.append(1) less('r') stack.append(cmd) store('r') z() stack.append(1) less('r') p() 

С jq :

 seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)' 

Чистый и короткий баш.

 f=$(cat numbers.txt) echo $(( ${f//$'\n'/+} )) 
 perl -lne '$x += $_; END { print $x; }' < infile.txt 

Мои пятнадцать центов:

 $ cat file.txt | xargs | sed -e 's/\ /+/g' | bc 

Пример:

 $ cat text 1 2 3 3 4 5 6 78 9 0 1 2 3 4 576 7 4444 $ cat text | xargs | sed -e 's/\ /+/g' | bc 5148 

BASH, если вы хотите сделать это командой (например, если вам нужно делать это часто):

 addnums () { local total=0 while read val; do (( total += val )) done echo $total } 

Затем использование:

 addnums < /tmp/nums 

Обычная баш-лайнер

 $ cat > /tmp/test 1 2 3 4 5 ^D $ echo $(( $(cat /tmp/test | tr "\n" "+" ) 0 )) 

Следующие работы в bash:

 I=0 for N in `cat numbers.txt` do I=`expr $I + $N` done echo $I 

Вы можете использовать num-utils, хотя это может быть излишним для того, что вам нужно. Это набор программ для управления числами в оболочке и может выполнять несколько отличных вещей, включая, конечно, их добавление. Это немного устарело, но они все еще работают и могут быть полезны, если вам нужно сделать что-то еще.

http://suso.suso.org/programs/num-utils/

Я сделал быструю оценку существующих ответов, которые

  • используйте только стандартные инструменты (извините за такие вещи, как lua или rocket ),
  • являются реальными однострочными,
  • могут добавить огромное количество чисел (100 миллионов) и
  • (я проигнорировал те, которые занимали больше минуты).

Я всегда добавлял цифры от 1 до 100 миллионов, которые выполнялись на моей машине менее чем за минуту для нескольких решений.

Вот результаты:

питон

 :; seq 100000000 | python -c 'import sys; print sum(map(int, sys.stdin))' 5000000050000000 # 30s :; seq 100000000 | python -c 'import sys; print sum(int(s) for s in sys.stdin)' 5000000050000000 # 38s :; seq 100000000 | python3 -c 'import sys; print(sum(int(s) for s in sys.stdin))' 5000000050000000 # 27s :; seq 100000000 | python3 -c 'import sys; print(sum(map(int, sys.stdin)))' 5000000050000000 # 22s :; seq 100000000 | pypy -c 'import sys; print(sum(map(int, sys.stdin)))' 5000000050000000 # 11s :; seq 100000000 | pypy -c 'import sys; print(sum(int(s) for s in sys.stdin))' 5000000050000000 # 11s 

Awk

 :; seq 100000000 | awk '{s+=$1} END {print s}' 5000000050000000 # 22s 

Paste & Bc

На моей машине закончилась нехватка памяти. Он работал на половину размера ввода (50 миллионов номеров):

 :; seq 50000000 | paste -s -d+ - | bc 1250000025000000 # 17s :; seq 50000001 100000000 | paste -s -d+ - | bc 3750000025000000 # 18s 

Так что, я думаю, это потребовало бы ~ 35 секунд для 100 миллионов номеров.

Perl

 :; seq 100000000 | perl -lne '$x += $_; END { print $x; }' 5000000050000000 # 15s :; seq 100000000 | perl -e 'map {$x += $_} <> and print $x' 5000000050000000 # 48s 

Рубин

 :; seq 100000000 | ruby -e "puts ARGF.map(&:to_i).inject(&:+)" 5000000050000000 # 30s 

С

Для сравнения я скомпилировал версию C и протестировал это, просто чтобы понять, насколько медленнее решения на основе инструментов.

 #include  int main(int argc, char** argv) { long sum = 0; long i = 0; while(scanf("%ld", &i) == 1) { sum = sum + i; } printf("%ld\n", sum); return 0; } 

 :; seq 100000000 | ./a.out 5000000050000000 # 8s 

Вывод

C, конечно, быстрее всего с 8s, но решение Pypy только добавляет очень немного накладных расходов примерно от 30% до 11 секунд . Но, если быть честным, Pypy не совсем стандарт. У большинства людей есть только CPython, который значительно медленнее (22s), точно так же быстро, как и популярное решение Awk.

Быстрое решение на основе стандартных инструментов – Perl (15s).

Я понимаю, что это старый вопрос, но мне нравится это решение, чтобы поделиться им.

 % cat > numbers.txt 1 2 3 4 5 ^D % cat numbers.txt | perl -lpe '$c+=$_}{$_=$c' 15 

Если есть интерес, я объясню, как это работает.

 sed 's/^/.+/' infile | bc | tail -1 

Чистый баш и в одном лайнере 🙂

 $ cat numbers.txt 1 2 3 4 5 6 7 8 9 10 $ I=0; for N in $(cat numbers.txt); do I=$(($I + $N)); done; echo $I 55 

Альтернативный чистый Perl, достаточно читаемый, без пакетов или опций:

 perl -e "map {$x += $_} <> and print $x" < infile.txt 

Для любителей Ruby

 ruby -e "puts ARGF.map(&:to_i).inject(&:+)" numbers.txt 

Я думаю, что AWK – это то, что вы ищете:

 awk '{sum+=$1}END{print sum}' 

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

Моя версия:

 seq -5 10 | xargs printf "- - %s" | xargs | bc 

Вы можете сделать это на python, если вам комфортно:

Не проверено, просто набрано:

 out = open("filename").read(); lines = out.split('\n') ints = map(int, lines) s = sum(ints) print s 

Себастьян указал на один лайнерский сценарий:

 cat filename | python -c"from fileinput import input; print sum(map(int, input()))" 

Следующее должно работать (при условии, что ваш номер является вторым полем в каждой строке).

 awk 'BEGIN {sum=0} \ {sum=sum + $2} \ END {print "tot:", sum}' Yourinputfile.txt 

Один вкладыш в ракетке:

 racket -e '(define (g) (define i (read)) (if (eof-object? i) empty (cons i (g)))) (foldr + 0 (g))' < numlist.txt 

C (не упрощенный)

 seq 1 10 | tcc -run <(cat << EOF #include  int main(int argc, char** argv) { int sum = 0; int i = 0; while(scanf("%d", &i) == 1) { sum = sum + i; } printf("%d\n", sum); return 0; } EOF) 
 $ cat n
 2
 4
 2
 7
 8
 9
 $ perl -MList::Util -le 'print List::Util::sum(<>)' < n 32 

Или вы можете ввести числа в командной строке:

 $ perl -MList::Util -le 'print List::Util::sum(<>)' 1 3 5 ^D 9 

Тем не менее, это один разрывает файл, поэтому неплохо использовать его для больших файлов. См . Ответ j_random_hacker, который позволяет избежать разрыва.

Сводка в режиме реального времени позволяет следить за ходом выполнения определенной задачи.

 $ cat numbers.txt 1 2 3 4 5 6 7 8 9 10 $ cat numbers.txt | while read new; do total=$(($total + $new)); echo $total; done 1 3 6 10 15 21 28 36 45 55 

(В этом случае нет необходимости устанавливать $total в 0. Если вы не можете получить $ total после финиша.)

Вы можете использовать свою привилегированную команду «expr», вам просто нужно сначала немного вставить вкладку:

 seq 10 | tr '[\n]' '+' | sed -e 's/+/ + /g' -e's/ + $/\n/' | xargs expr 

Процесс:

  • «tr» заменяет символы eoln символом +
  • sed накладывает «+» на пробелы с каждой стороны, а затем удаляет финальную + из строки
  • xargs вставляет входной канал в командную строку для использования expr.

C ++ (упрощенный):

 echo {1..10} | scc 'WRL n+=$0; n' 

Проект SCC – http://volnitsky.com/project/scc/

SCC – это оценщик fragmentов кода C ++ в командной строке

  • Какой код возврата мне нужен в PS *, чтобы убедиться, что терминал вернулся в обычные настройки в командной строке?
  • Запустить скрипт как root через ADB
  • Scp между двумя удаленными хостами от моего (третьего) компьютера
  • Как выполнить итерацию по диапазону чисел, определяемых переменными в Bash?
  • Когда подстановка команд порождает больше подоболочек, чем одни и те же команды в изоляции?
  • Использование curl для загрузки данных POST с файлами
  • $ {1: + "$ @"} в / bin / sh
  • Что такое / dev / null 2> & 1?
  • Почему у нас есть логин, не-логин, интерактивные и неинтерактивные оболочки bash?
  • Сделайте хвост -F до соответствия рисунку
  • Как обрабатывать каждую строку, полученную в результате команды grep
  • Interesting Posts

    Как открыть URL-адрес по расписанию в браузере по умолчанию?

    Разница между регулярным выражением и

    Скопированный профиль пользователя, теперь получите «невозможно получить доступ к устройствам … соответствующие разрешения» в системных файлах

    React не перезагружает данные компонента при изменении параметров маршрута или изменении запроса

    Как добавить функцию в jQuery?

    Excel vba: копировать строки, если данные соответствуют значениям в столбце на другом листе

    Зачем нам нужно использовать boost :: asio :: io_service :: work?

    Как изменить временную метку в dll или exe?

    Как преобразовать DateTime в число секунд с 1970 года?

    Есть ли способ удалить запрещенные разрешения из группы для папки, если у меня нет доступа?

    Почему аргумент типа карты C ++ требует пустого конструктора при использовании ?

    Как выполнять определенную задачу каждый день в определенное время с помощью ScheduledExecutorService?

    Как выбрать случайный элемент в std :: set?

    Ctrl-Space в Eclipse без нажатия Ctrl-пробела

    IFilterProvider и разделение проблем

    Давайте будем гением компьютера.