Самая короткая команда для вычисления суммы столбца вывода на Unix?

Я уверен, что есть быстрый и простой способ вычислить сумму столбца значений в Unix-системах (возможно, используя что-то вроде awk или xargs), но написание оболочки script для синтаксического анализа строки строки за строкой - единственное, что приходит в голову на данный момент.

Например, какой самый простой способ изменить приведенную ниже команду, чтобы вычислить и отобразить общее количество для столбца SEGSZ (70300)?

ipcs -mb | head -6
IPC status from /dev/kmem as of Mon Nov 17 08:58:17 2008
T         ID     KEY        MODE        OWNER     GROUP      SEGSZ
Shared Memory:
m          0 0x411c322e --rw-rw-rw-      root      root        348
m          1 0x4e0c0002 --rw-rw-rw-      root      root      61760
m          2 0x412013f5 --rw-rw-rw-      root      root       8192

Ответ 1

ipcs -mb | tail +4 | awk '{ sum += $7 } END { print sum }'

Или без хвоста:

ipcs -mb | awk 'NR > 3 { sum += $7 } END { print sum }'

Использование awk с bc для получения произвольных длинных результатов (кредиты Jouni K.):

ipcs -mb | awk 'NR > 3 { print $7 }' | paste -sd+ | bc

Ответ 2

Я попытался бы построить строку вычисления и передать ее на bc следующим образом:

  • grep строки, содержащие числа
  • удалять все символы до (и после) номера на каждой строке
  • xargs результат (чтобы получить строку чисел, разделенных пробелами)
  • tr анслировать пробелы символами '+'
  • хороший аппетит bc!

ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' + | bc

Похоже, что это немного дольше, чем решение awk, но для всех, кто не может читать (и понимать) нечетный код awk, это может быть проще понять...: -)

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

  • echo $(( $(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) )) или
  • SUM=$(( $(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) )) или
  • (( SUM=$(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) ))

Интервал после и перед двойными скобками необязателен.

Ответ 3

У меня есть утилита script, которая просто добавляет все столбцы. Обычно достаточно легко захватить тот, который вы хотите, из однострочного вывода. В качестве бонуса признаются некоторые SI-суффиксы.

#!/usr/bin/awk -f
# Sum up numerical values by column (white-space separated)
#
# Usage:  $0 [file ...]
#
# stern, 1999-2005

{
    for(i = 1; i <= NF; ++i) {
        scale = 1
        if ($i ~ /[kK]$/) { scale = 1000 }
        if ($i ~ /[mM]$/) { scale = 1000*1000 }
        if ($i ~ /[gG]$/) { scale = 1000*1000*1000 }
        col[i] += scale * $i;
    }
    if (NF > maxnf) maxnf = NF;
}

END {
    for(i = 1; i <= maxnf; ++i) { printf " %.10g", col[i] }
    print "";
}

Пример с настраиваемым разделителем полей:

$ head /etc/passwd | addcol -F:
0 0 45 39 0 0 0

Ответ 4

Решение Python

#!/usr/bin/env python
text= file("the_file","r")
total= 0
for line in text:
    data = line.split()
    if data[0] in ('T', 'Shared', 'IPC'): continue
    print line
    segsize= int(data[6])
    total += segsize
print total

В большинстве дистрибутивов Linux есть Python.

Если вы хотите обработать stdin как часть конвейера, используйте

import sys
total = 0
for line in sys.stdin:
   ...etc...

Если вы хотите предположить, что всегда есть три строки заголовка:

import sys
total = 0
for line in sys.stdin.readlines()[3:]:
    total += int(line.split()[6])
print total

Однострочник:

import sys; print sum( [int(line.split()[6]) for line in sys.stdin.splitlines()[3:]] )

Ответ 5

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

  • tail (чтобы получить нужные строки)
  • tr (для сокращения нескольких последовательных пространств до одного)
  • cut (чтобы получить только нужный столбец)
  • вставить (чтобы объединить каждую строку с знаком +)
  • bc (для выполнения фактического расчета)

ipcs не выводит результат в моей системе, поэтому я просто покажу его с помощью df:

# df
Filesystem     1K-blocks    Used Available Use% Mounted on
rootfs          33027952 4037420  27312812  13% /
udev               10240       0     10240   0% /dev
tmpfs             102108     108    102000   1% /run
/dev/xvda1      33027952 4037420  27312812  13% /
tmpfs               5120       0      5120   0% /run/lock
tmpfs             204200       0    204200   0% /run/shm
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client1/web1/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client1/web2/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client1/web3/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client1/web4/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client2/web5/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client2/web6/log
# df | tail -n +2 | tr -s ' ' | cut -d ' ' -f 2 | paste -s -d+ | bc
264545284

Я знаю, что выполнение этого конкретного вычисления в моей системе действительно не имеет смысла, но оно показывает концепцию.

Все части этого решения были показаны в других ответах, но никогда в этой комбинации.

Ответ 6

Вы можете начать с запуска данных с помощью cut, которые по крайней мере обрезают столбцы.

Затем вы можете передать это в grep, зачеркивая нечисло.

Тогда... ну, тогда я не уверен. Возможно, это можно будет передать на bc. Если нет, ее можно было бы передать оболочке script, чтобы добавить каждый элемент.

Если вы использовали tr, чтобы изменить новые строки (\n) на пробелы (), и передал их через xargs в ваш script, который будет циклически, пока не будет больше входных данных, добавив каждый из них, вы может иметь ответ.

Итак, что-то похожее на следующее:

cat <whatever> | cut -d'\t` -f7 | grep -v <appropriate-character-class> | tr '\n' ' ' | xargs script-that-adds-arguments

У меня могут быть неправильные флаги cut, но man - ваш друг:)

Ответ 7

Вы можете найти его в любой онлайн-ссылке awk:

ipcs | awk '
BEGIN { sum = 0 }
/0x000000/ { sum = sum + $2 }
END {print sum}'

Ответ 8

Спасибо за однострочный Python выше!. Это помогло мне легко проверить используемое пространство на моем диске. Вот смешанный shell/Python однострочный, который делает это - подсчитывает используемое пространство на устройстве /dev/sda в мегабайтах. Мне потребовалось некоторое время, прежде чем я узнал об этом, так что, возможно, кто-то тоже найдет это полезным.

df -h -B 1M | grep dev/sda | tr -s ' '| cut -d' ' -f3 |python -c "import sys; print sum([int(num) for num in sys.stdin.readlines()])"

или больше оболочки Python/less:

 df -h -B 1M | python -c "import sys; print sum([int(l.split()[2]) for l in sys.stdin.readlines() if '/dev/sda' in l])"

Еще раз спасибо!

Ответ 9

Для суммирования значений в столбце вы можете использовать GNU datamash. Поскольку первые четыре строки не содержат значений, которые вы хотите суммировать, мы удаляем их с помощью tail +4.

ipcs -mb  | tail +4 | datamash -W sum 7

Опция -W устанавливает разделитель поля на (возможно, несколько) пробелов.

Ответ 10

Если у вас есть несколько столбцов, которые вы хотите суммировать, вы можете использовать:

input_command | awk '{s1+=$1;s2+=$2;s3+=$3;s4+=$4;s5+=$5}END{print s1,s2,s3,s4,s5}'

который будет работать, если вы хотите сложить столбцы 1–5.