Самая короткая команда для вычисления суммы столбца вывода на 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.