2008-11-17 8 views
43

Estoy seguro de que hay una forma rápida y fácil de calcular la suma de una columna de valores en sistemas Unix (usando algo como awk o xargs), pero escribir un guión de shell para analizar las filas línea por línea es el único Lo que viene a la mente en este momento.¿El comando más corto para calcular la suma de una columna de salida en Unix?

Por ejemplo, ¿cuál es la forma más sencilla de modificar el siguiente comando para calcular y visualizar 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 

Respuesta

77
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 a Jouni K.): Solución Python

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

+1 .. eliminado mi duplicado :-) – toolkit

+0

Gracias, muy útil! Ejecutando ese comando, obtengo este resultado: 6.59246e + 08. ¿Hay alguna forma de forzar a awk a mostrar el valor exacto (en lugar de la notación científica)? –

+0

Andrew, hay una función printf para awk: http://www.gnu.org/software/gawk/manual/gawk.html#Printf –

1

Se podría empezar ejecutando los datos a través de cut - lo que al menos recortar las columnas hacia abajo.

Debería ser capaz de canalizar eso en grep, eliminando los valores no numéricos.

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

Si utilizó tr para cambiar los saltos de línea (\n) a espacios (), e hilo que a través de xargs en la secuencia de comandos que se repite hasta que no hay más entradas, la adición de cada uno, es posible que tenga una respuesta.

Por lo tanto, algo parecido a lo siguiente:

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

que pueden tener las banderas cut un poco mal - pero man es su amigo :)

2

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

distribuciones de Linux tienen más de Python.

Si desea procesar la entrada estándar como parte de un pipline, utiliza

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

Si desea asumir que siempre hay 3 líneas de cabecera:

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

de una sola línea:

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

Puede buscarlo en cualquier línea de referencia awk:

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

Tengo un script de utilidad que simplemente suma todas las columnas. Por lo general, es bastante fácil obtener el que desea de la salida de una línea. Como beneficio adicional, algunos sufijos SI son reconocidos.

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

Ejemplo con separador de campo personalizado:

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

# Uso: $ 0 [archivo ...] <- No hay "-F" ... ¿Puedes aclarar el uso? ¿Qué banderas son compatibles? –

0

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

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!

12

me gustaría tratar de construir una cadena de cálculo y alimentarlo a bc de la siguiente manera:

  1. grep las líneas que contienen los números
  2. SED de distancia todos los caracteres antes (y después de) el número en cada línea
  3. xargs el resultado (para obtener una cadena de números separados por espacios en blanco)
  4. tr anslate 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 ligeramente más larga que la solución awk, pero para todo el mundo que no saben leer (y entender) la extraña código awk esto puede ser más fácil de entender .. . :-)

Si bc no está instalado se puede utilizar 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 ' ' +)))

La separación después y antes de los dobles paréntesis es opcional.

1

Sé que esta pregunta es un poco anticuada, pero no puedo ver "mi" respuesta aquí, así que decidí publicar de todos modos.Me gustaría ir con una combinación de

  • cola (para obtener las líneas que necesita)
  • tr (a encoger múltiples espacios consequitive a uno)
  • corte (para obtener sólo la columna es necesario)
  • pasta (para concatenar cada línea con un signo +)
  • bc (para hacer el cálculo real)

ipcs no da una salida en mi sistema, por lo que sólo va demostración 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 

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

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

Cuestiones relacionadas