Usare awk per sommare i valori di una colonna, in base ai valori di un'altra colonna


64

Sto cercando di sommare determinati numeri in una colonna usando awk. Vorrei sommare solo la colonna 3 dei "fabbri" per ottenere un totale di 212. Posso sommare l'intera colonna usando awkma non solo i "fabbri". Io ho:

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

Anche io sto usando stucco. Grazie per tutto l'aiuto.

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

Risposte:


82
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • La -Fbandiera imposta il separatore di campo; L'ho messo tra virgolette singole perché è un personaggio shell speciale.
  • Quindi $1 ~ /smiths/applica il seguente {blocco di codice} solo alle righe in cui il primo campo corrisponde al regex /smiths/.
  • Il resto è uguale al tuo codice.

Nota che dal momento che non stai davvero usando una regex qui, solo un valore specifico, potresti usare altrettanto facilmente:

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

Che controlla l'uguaglianza delle stringhe. Ciò equivale all'utilizzo del regex /^smiths$/, come menzionato in un'altra risposta, che include l' ^ancoraggio per abbinare solo l'inizio della stringa (l'inizio del campo 1) e l' $ancoraggio per abbinare solo la fine della stringa. Non sono sicuro di quanto tu abbia familiarità con le regex. Sono molto potenti, ma in questo caso è possibile utilizzare un controllo dell'uguaglianza delle stringhe altrettanto facilmente.


3
A proposito, il mio riferimento preferito di awk preferito è grymoire.com/Unix/Awk.html . Pagina molto utile.
Carattere jolly

1
Grazie @Wildcard! Sono stato in grado di aggregare ordinatamente una dimensione non compressa di file particolari nel grande archivio zip in base ai tuoi consigli :) unzip -lv /appl/tmp/data.lar | grep documentlibrary | awk '{sum += $1} END {print sum/1024/1024}'
Pawel,

15

Un altro approccio consiste nell'utilizzare array associativi awk, maggiori informazioni qui . Questa riga produce l'output desiderato:

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

Come effetto collaterale, l'array memorizza tutti gli altri valori:

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

Produzione:

smiths 212
denniss 100
olivert 10

Questa è la risposta giusta
PoVa

5

Molto bene finora. Tutto quello che devi fare è aggiungere un selettore prima del blocco per aggiungere la somma. Qui controlliamo che il primo argomento contenga solo "fabbri":

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

Potresti accorciarlo un po 'specificando il separatore di campo come opzione. In awkgenerale è una buona idea inizializzare le variabili sulla riga di comando:

awk -F'|' '$1 ~ /^smiths$/ {sum+=$3} END {print sum}'

0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F opzione per specificare il separatore.
  • $NF è per "ultima colonna".

1
cate grepnon sono necessari qui.
Andrey,

Perché grep non è necessario @Andrey? OP vuole aggiungere solo righe "fabbri". Dovresti modificare l'istruzione awk, giusto?
EL

1
@EL sì, l'istruzione awk dovrebbe essere modificata /smiths/{...}se la chiamata grep non è presente. Questa è una modifica banale, ma offre vantaggi significativi: riduce il numero di processi in esecuzione, semplifica il controllo degli errori e rende il codice più chiaro.
Andrey,

0

Personalmente preferirei mantenere la awksezione il più semplice possibile e fare il più possibile senza di essa. La logica combinata non sfrutta la potenza delle condotte Unix ed è quindi più difficile da comprendere, eseguire il debug o modificare per casi d'uso strettamente correlati.

cat filename.txt | perl -pe 's{.*|}{}g' | awk '{sum+=$1} END {print sum}'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.