Команда оболочки для суммирования целых чисел, по одному на строку? - PullRequest
765 голосов
/ 16 января 2009

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

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

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

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


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

Ответы [ 42 ]

1198 голосов
/ 16 января 2009

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

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

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

awk '{s+=$1} END {printf "%.0f", s}' mydatafile
622 голосов
/ 16 января 2009

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

paste -s -d+ infile | bc

В качестве альтернативы, когда трубопровод от стандартного ввода,

<commands> | paste -s -d+ - | bc
112 голосов
/ 16 января 2009

Однострочная версия на Python:

$ python -c "import sys; print(sum(int(l) for l in sys.stdin))"
77 голосов
/ 11 августа 2014

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

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
73 голосов
/ 16 января 2009

Обычный удар:

$ 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
63 голосов
/ 17 января 2009
dc -f infile -e '[+z1<r]srz1<rp'

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

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

Выражение [+z1<r]srz1<rp делает следующее :

[   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
  <r  pop two values and execute register r if the original top-of-stack (1)
      is smaller
]   end of the string, will push the whole thing to the stack
sr  pop a value (the string above) and store it in register r
z   push the current stack depth again
1   push 1
<r  pop two values and execute register r if the original top-of-stack (1)
    is smaller
p   print the current top-of-stack

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

  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()
51 голосов
/ 27 октября 2014

С JQ :

seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'
45 голосов
/ 20 декабря 2012

Чистый и короткий удар.

f=$(cat numbers.txt)
echo $(( ${f//$'\n'/+} ))
36 голосов
/ 16 января 2009
perl -lne '$x += $_; END { print $x; }' < infile.txt
25 голосов
/ 21 августа 2013

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

$ 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...