Использование awk для суммирования значений столбца на основе значений другого столбца

64

Я пытаюсь суммировать определенные числа в столбце, используя awk. Я хотел бы суммировать только столбец 3 «кузнецов», чтобы получить в общей сложности 212. Я могу суммировать весь столбец, используя awkне только «кузнецов». У меня есть:

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

Также я использую замазку. Спасибо за любую помощь.

smiths|Login|2
olivert|Login|10
denniss|Payroll|100
smiths|Time|200
smiths|Logout|10
Джейк
источник

Ответы:

82
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • -FФлаг устанавливает разделитель полей; Я поместил его в одинарные кавычки, потому что это специальный символ оболочки.
  • Затем $1 ~ /smiths/применяет следующий {кодовый блок} только к строкам, где первое поле соответствует регулярному выражению /smiths/.
  • Остальное так же, как ваш код.

Обратите внимание, что поскольку вы на самом деле здесь не используете регулярное выражение, а просто конкретное значение, вы можете также легко использовать:

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

Который проверяет равенство строк. Это эквивалентно использованию регулярного выражения /^smiths$/, как упомянуто в другом ответе, который включает в себя привязку, которая соответствует ^только началу строки (начало поля 1), и $привязку, чтобы соответствовать только концу строки. Не уверен, насколько вы знакомы с регулярными выражениями. Они очень мощные, но для этого случая вы можете использовать проверку на равенство строк так же легко.

Wildcard
источник
3
Кстати, моя любимая ссылка на awk - grymoire.com/Unix/Awk.html . Очень полезная страница.
Подстановочный
1
Спасибо @Wildcard! Я смог аккуратно собрать несжатый размер отдельных файлов в большой zip-архив, основываясь на вашем совете :) unzip -lv /appl/tmp/data.lar | grep documentlibrary | awk '{sum += $1} END {print sum/1024/1024}'
Pawel
15

Другой подход заключается в использовании ассоциативных массивов awk, подробнее здесь . Эта строка производит желаемый результат:

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

Как побочный эффект, массив хранит все другие значения:

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

Выход:

smiths 212
denniss 100
olivert 10
Андрей
источник
Это правильный ответ
PoVa
5

Очень хорошо, пока. Все, что вам нужно сделать, это добавить селектор перед блоком, чтобы добавить сумму. Здесь мы проверяем, что первый аргумент содержит только «кузнецы»:

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

Вы можете сократить это, указав разделитель полей в качестве опции. В awkэто вообще хорошая идея , чтобы инициализировать переменные в командной строке:

awk -F'|' '$1 ~ /^smiths$/ {sum+=$3} END {print sum}'
RobertL
источник
0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F Возможность указать разделитель.
  • $NF для "последнего столбца".
forzagreen
источник
1
catи grepне нужны здесь.
Андрей
Почему grep не нужен @Andrey? ОП хочет добавить только строки "кузнецов". Вам нужно изменить выражение awk, верно?
EL
1
@EL Да, оператор awk должен быть изменен на, /smiths/{...}если вызов grep отсутствует. Это тривиальная модификация, но она дает значительные преимущества: уменьшает количество запущенных процессов, упрощает контроль ошибок и делает код более понятным.
Андрей
0

Я лично предпочел бы сохранить awkраздел как можно более простым и делать как можно больше без него. Логика Comingled не использует возможности конвейеров Unix и, следовательно, сложнее понять, отладить или изменить для тесно связанных случаев использования.

cat filename.txt | perl -pe 's{.*|}{}g' | awk '{sum+=$1} END {print sum}'
Шридхар Сарнобат
источник