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

StackOverflow https://stackoverflow.com/questions/295781

  •  08-07-2019
  •  | 
  •  

Вопрос

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

Например, как проще всего изменить приведенную ниже команду, чтобы вычислить и отобразить итоговую сумму для столбца 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
Это было полезно?

Решение

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

Другие советы

Я бы попытался построить строку расчета и передать ее До нашей эры следующее:

  1. grep строки, содержащие цифры
  2. СЭД убрать все символы до (и после) числа в каждой строке
  3. xargs результат (чтобы получить строку чисел, разделенных пробелами)
  4. тр заменить пробелы символами «+»
  5. приятного аппетита До нашей эры!

ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' + | 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 ' ' +) ))

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

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

#!/usr/bin/awk -f
# Sum up numerical values by column (white-space separated)
#
# Usage:  
$ head /etc/passwd | addcol -F:
0 0 45 39 0 0 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 ""; }

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

<*>

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.

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

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

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

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:]] )

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

  • хвост (чтобы получить нужные строки)
  • tr (чтобы сжать несколько последовательных пробелов до одного)
  • вырезать (чтобы получить только нужный столбец)
  • вставить (чтобы объединить каждую строку с + знак)
  • 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

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

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

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

После этого вы сможете передать это в grep , удаляя нечисловые числа.

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

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

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

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

Возможно, у меня немного неправильные флаги cut , но man - твой друг :)

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

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

Спасибо за однострочник Python выше! Это помогло мне легко проверить используемое место на моем диске. Вот смешанная оболочка / 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 shell:

 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])"

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

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

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

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

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

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

, который будет работать, если вы хотите суммировать столбцы 1 & # 8211; 5.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top