Pergunta

Eu tenho certeza que é uma maneira rápida e fácil de calcular a soma de uma coluna de valores em sistemas Unix (usando algo como awk ou xargs talvez), mas escrever um script shell para analisar a linha de linhas por linha é a única coisa que vem à mente no momento.

Por exemplo, qual é a maneira mais simples de modificar o comando a seguir para calcular e exibir o total para a coluna 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
Foi útil?

Solução

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

ou sem cauda:

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

Usando o awk com bc ter arbitrárias longos resultados (créditos para Jouni K.):

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

Outras dicas

Gostaria de tentar construir uma seqüência de cálculo e alimentá-lo para bc como segue:

  1. grep as linhas que contêm os números
  2. sed de distância todos os caracteres antes (e depois) o número em cada linha
  3. xargs o resultado (para obter uma seqüência de números separados por espaços em branco)
  4. tr anslate os espaços em branco para caracteres '+'
  5. bom apetite bc !

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

Parece que este é ligeiramente mais longo do que o awk solução, mas para todos aqueles que não podem ler (e entender) o estranho awk Código isso pode ser mais fácil de entender ...: -)

Se bc não está instalado, você pode usar parênteses duplos no passo 5 acima para calcular o resultado:

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

O espaçamento antes e após os parênteses duplos é opcional.

Eu tenho um script utilitário que simplesmente acrescenta-se todas colunas. Geralmente é fácil o suficiente para pegar o que deseja a partir da saída de uma linha. Como um bônus, alguns SI-sufixos são reconhecidos.

#!/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 "";
}

Exemplo com separador de campo personalizado:

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

Python Solução

#!/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

distros Linux têm mais Python.

Se você quiser stdin processo como parte de um pipline, uso

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

Se você quiser assumir que há sempre linhas 3 de cabeçalho:

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

One-liner:

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

Eu sei que esta questão é um pouco datada, mas eu não posso ver "meu" resposta aqui, então eu decidi postar no entanto. Eu iria com uma combinação de

  • cauda (para obter as linhas que você precisa)
  • tr (para encolher múltiplos espaços consequitive a um)
  • corte (para obter apenas a coluna necessário)
  • colar (para concatenar cada linha com um sinal +)
  • bc (para fazer o cálculo real)

ipcs não dá uma saída no meu sistema, então eu vou demonstrar isso com 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

Eu sei fazer este cálculo especial no meu sistema realmente não faz sentido, mas mostra o conceito.

Todas as peças desta solução foram mostrados em outras respostas, mas nunca nessa combinação.

Você poderia começar por executar os dados através cut - que seria, pelo menos aparar as colunas para baixo.

Você deve então ser capaz de tubo que em grep, despindo-out não-numéricos.

Então ... bem, então eu não tenho certeza. Pode ser possível tubo que a bc. Se não, ele certamente poderia ser entregue a um shell script para adicionar cada item.

Se você usou tr para alterar as novas linhas (\n) para espaços () e canalizada que através xargs em seu script que voltas até que não haja mais entradas, acrescentando cada um deles, você pode ter uma resposta.

Assim, algo parecido com o seguinte:

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

Eu posso ter as bandeiras cut ligeiramente errado - mas man é seu amigo:)

Você poderia procurá-lo em qualquer referência awk on-line:

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

Obrigado pelo Python one-liner acima !. Ele me ajudou a verificar fácil o espaço usado no meu disco. Aqui é um shell mista / Python one-liner, que fazer isso - conta usados ??espaço no dispositivo / dev / sda em megabytes. Levei algum tempo, antes que eu encontrei-o para fora, por isso, talvez alguém acha isso útil também.

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

ou mais Python / menos 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])"

Mais uma vez obrigado!

Para somar valores em uma coluna você pode usar GNU datamash. Desde as primeiras quatro linhas não contêm valores que pretende resumir, nós removê-los com tail +4.

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

A opção -W define o delimitador de campo para (possivelmente múltiplas) espaços em branco.

Se você tem específico, várias colunas que você deseja resumir, você pode usar:

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

que irá funcionar se você deseja somar colunas 1-5.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top