Pregunta

Estoy seguro de que hay una manera rápida y fácil de calcular la suma de una columna de valores en sistemas Unix (usando algo como awk o xargs quizás), pero escribir un script de shell para analizar las filas línea por línea es lo único que viene a la mente en este momento.

Por ejemplo, ¿cuál es la forma más sencilla de modificar el siguiente comando para calcular y mostrar el total de la columna 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
¿Fue útil?

Solución

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

O sin cola:

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

Uso de awk con bc para obtener resultados largos arbitrarios (créditos para Jouni K. ):

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

Otros consejos

Intentaría construir una cadena de cálculo y alimentarla a bc de la siguiente manera:

  1. grep las líneas que contienen los números
  2. sed ausente todos los caracteres antes (y después) del número en cada línea
  3. xargs el resultado (para obtener una cadena de números separados por espacios en blanco)
  4. tr responde los espacios en blanco a los caracteres '+'
  5. buen apetito bc !

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

Parece que esto es un poco más largo que la solución awk , pero para todos los que no pueden leer (y entender) el código extraño awk , esto puede ser más fácil de entender ... :-)

Si bc no está instalado, puede usar paréntesis dobles en el paso 5 anterior para calcular el resultado:

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

El espacio después y antes del paréntesis doble es opcional.

Tengo un script de utilidad que simplemente agrega todas columnas. Por lo general, es bastante fácil obtener el que desea de la salida de una línea. Como beneficio adicional, se reconocen algunos sufijos 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 ""; }

Ejemplo con separador de campo personalizado:

<*>

Solución 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

La mayoría de las distribuciones de Linux tienen Python.

Si desea procesar la entrada estándar como parte de una canalización, use

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

Si quiere suponer que siempre hay 3 líneas de encabezado:

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

Sé que esta pregunta está algo anticuada, pero no puedo ver "mi" Respondo aquí, así que decidí publicar. Me gustaría ir con una combinación de

  • cola (para obtener las líneas que necesita)
  • tr (para reducir múltiples espacios consecutivos a uno)
  • cortar (para obtener solo la columna necesaria)
  • pegar (para concatenar cada línea con un signo + )
  • bc (para hacer el cálculo real)

ipcs no da una salida en mi sistema, así que lo demostraré con 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

Sé que hacer este cálculo en particular en mi sistema realmente no tiene sentido, pero muestra el concepto.

Todas las partes de esta solución se han mostrado en las otras respuestas, pero nunca en esa combinación.

Podría comenzar ejecutando los datos a través de cut , que al menos recortaría las columnas.

Debería poder canalizar eso en grep , eliminando los no numéricos.

Entonces ... bueno, entonces no estoy seguro. Podría ser posible canalizar eso a bc . De lo contrario, sin duda podría entregarse a un script de shell para agregar cada elemento.

Si usó tr para cambiar las nuevas líneas ( \ n ) a espacios ( ), y lo canalizó a través de xargs en su script que bucles hasta que no haya más entradas, agregando cada una, puede tener una respuesta.

Entonces, algo similar a lo siguiente:

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

Es posible que las banderas cut estén un poco mal, pero man es tu amigo :)

Puede buscarlo en cualquier referencia awk en línea:

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

¡Gracias por la línea de Python de arriba !. Me ayudó a verificar fácilmente el espacio usado en mi disco. Aquí hay una línea mixta de shell / Python, que hace esto: cuenta el espacio utilizado en el dispositivo / dev / sda en megabytes. Me tomó algo de tiempo, antes de descubrirlo, así que tal vez alguien también encuentre esto útil.

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

o más 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])"

¡Gracias de nuevo!

Para sumar valores en una columna, puede usar GNU datamash. Como las primeras cuatro líneas no contienen valores que desea resumir, las eliminamos con tail +4 .

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

La opción -W establece el delimitador de campo en (posiblemente múltiples) espacios en blanco.

Si tiene columnas específicas y múltiples que desea sumar, puede usar:

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

que funcionará si desea sumar las columnas 1 & # 8211; 5.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top