Usar awk para sumar los valores de una columna, en función de los valores de otra columna

64

Estoy tratando de sumar ciertos números en una columna usando awk. Me gustaría sumar solo la columna 3 de los "herreros" para obtener un total de 212. Puedo sumar toda la columna usando awkpero no solo los "herreros". Yo tengo:

awk 'BEGIN {FS = "|"} ; {sum+=$3} END {print sum}' filename.txt

También estoy usando masilla. Gracias por cualquier ayuda.

smiths|Login|2
olivert|Login|10
denniss|Payroll|100
smiths|Time|200
smiths|Logout|10
jake
fuente

Respuestas:

82
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • La -Fbandera establece el separador de campo; Lo pongo entre comillas simples porque es un personaje especial de shell.
  • Luego $1 ~ /smiths/aplica el siguiente {bloque de código} solo a las líneas donde el primer campo coincide con la expresión regular /smiths/.
  • El resto es igual a tu código.

Tenga en cuenta que dado que realmente no está usando una expresión regular aquí, solo un valor específico, podría usar con la misma facilidad:

awk -F '|' '$1 == "smiths" {sum += $3} END {print sum}' inputfilename

Que verifica la igualdad de la cadena. Esto es equivalente a usar la expresión regular /^smiths$/, como se menciona en otra respuesta, que incluye el ^ancla para que solo coincida con el inicio de la cadena (el inicio del campo 1) y el $ancla para que solo coincida con el final de la cadena. No estoy seguro de qué tan familiarizado está con las expresiones regulares. Son muy potentes, pero para este caso podría usar una verificación de igualdad de cadena con la misma facilidad.

Comodín
fuente
3
Por cierto, mi referencia favorita de awk es grymoire.com/Unix/Awk.html . Página muy útil
Comodín el
1
Gracias @Wildcard! Pude agregar de forma ordenada un tamaño sin comprimir de archivos particulares en un gran archivo zip basado en su consejo :) unzip -lv /appl/tmp/data.lar | grep documentlibrary | awk '{sum += $1} END {print sum/1024/1024}'
Pawel
15

Otro enfoque es utilizar matrices asociativas awk, más información aquí . Esta línea produce la salida deseada:

awk -F '|' '{a[$1] += $3} END{print a["smiths"]}' filename.txt

Como efecto secundario, la matriz almacena todos los demás valores:

awk -F '|' '{a[$1] += $3} END{for (i in a) print i, a[i]}' filename.txt

Salida:

smiths 212
denniss 100
olivert 10
Andrey
fuente
Esta es la respuesta correcta
PoVa
5

Muy bien hasta ahora. Todo lo que necesita hacer es agregar un selector antes del bloque para agregar la suma. Aquí comprobamos que el primer argumento contiene solo "herreros":

awk 'BEGIN {FS = "|"} ; $1 ~ /^smiths$/ {sum+=$3} END {print sum}'

Puede acortar esto un poco especificando el separador de campo como una opción. En awkgeneral, es una buena idea inicializar variables en la línea de comando:

awk -F'|' '$1 ~ /^smiths$/ {sum+=$3} END {print sum}'
RobertL
fuente
0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F opción para especificar separador.
  • $NF es para la "última columna".
forzagreen
fuente
1
caty grepson innecesarios aquí
Andrey
¿Por qué es innecesario grep @Andrey? OP quiere agregar solo filas de "herreros". Tendría que modificar la declaración awk, ¿verdad?
EL
1
@EL sí, la instrucción awk debería modificarse /smiths/{...}si la llamada grep no está allí. Esta es una modificación trivial, pero proporciona beneficios significativos: disminuye el número de procesos en ejecución, simplifica el control de errores y aclara el código.
Andrey
0

Personalmente, preferiría mantener la awksección lo más simple posible y hacer todo lo que pueda sin ella. La lógica combinada no aprovecha el poder de las tuberías de Unix y, por lo tanto, es más difícil de entender, depurar o modificar para casos de uso estrechamente relacionados.

cat filename.txt | perl -pe 's{.*|}{}g' | awk '{sum+=$1} END {print sum}'
Sridhar Sarnobat
fuente