Я пытаюсь стать немного более искусным с awk. Я сделал этот документ в формате .txt, который назвал food.txt, и меня раздражает, что я не могу сообразить, как сложить цены на продукты. Возьмем, к примеру, этот текстовый файл:

Milk dairy 3.89
Cheese dairy 2.12
Eggs produce 1.28
Yogurt dairy 1.49
Chicken produce 2.19
Muffin pastries 0.49
Cookie pastries 0.99

Первая строка/поле — это название товара, вторая строка/поле — категория, а последняя строка/поле — цена.

Я хочу иметь возможность делать две вещи.

Сначала я хочу сложить все цены в файле вместе, а затем найти среднее значение. У меня должно получиться 1,78 (округлено).

Во-вторых, я хочу сложить цены на все молочные продукты и найти среднюю цену молочных продуктов. В этом случае мой выход должен быть 2,50.

Я новичок в awk, поэтому не уверен, что мой текстовый документ нуждается в доработке или нет. Я сделал это сам, просто ради эксперимента.

Вот код, который я пробовал, и я не уверен, почему он не работает.

BEGIN{ avg = 0 }

{
   total = 0
     for(i = 3; i <= NF; i++)
       if ($2 == "dairy")
       total = total +$i
   avg += total
}

END{
        print "Total Dairy Price Average =  $" avg/NR
}

Я полагал, что, начиная с третьего поля, если второе поле было молочным, оно установило бы итог = итог+$i. Тогда среднее += общее. Но когда я запускаю это, оно дает мне что-то вроде 1.07, что очень далеко.

0
MC10 7 Ноя 2019 в 21:56

4 ответа

Awk подход:

$ awk '{ cat=$(NF-1); a[cat] += $NF; sum += $NF; b[cat]++ }
       END{ for (cat in a) print cat, a[cat]/b[cat]; print "all avg", sum/NR }' file

Выход:

dairy 2.5
produce 1.735
pastries 0.74
all avg 1.77857
2
RomanPerekhrest 7 Ноя 2019 в 21:47
Я научился использовать awk в файлах сценариев. Не могли бы вы сделать мне одолжение и показать, как будет выглядеть ваш awk-подход в виде файла сценария? Я привык запускать такие вещи, как «awk -f file.awk file.txt». Вы понимаете, о чем я?
 – 
MC10
7 Ноя 2019 в 21:49

Сначала я хочу сложить все цены в файле вместе, а затем найти среднее значение. У меня должно получиться 1,78 (округлено).

Обратите внимание, что NR содержит текущий номер строки при обработке файла, в предложении END будет указано общее количество строк, например:

awk '{ sum+=$3 } END { print sum, sum/NR }'

Или с округленными числами:

awk '{ sum+=$3 } END { print sum, sum/NR }' OFMT='%.2f'

Во-вторых, я хочу сложить цены на все молочные продукты и найти среднюю цену молочных продуктов. В этом случае мой выход должен быть 2,50.

Вы почти не используете какие-либо встроенные функции, которые поставляются с awk, например. каждый оператор состоит из boolean_expression { actions }. Таким образом, чтобы действовать только в строках, где $2 == "dairy":

awk '$2 == "dairy" { sum+=$3; count++ } END { print sum, sum/count }'
0
Thor 7 Ноя 2019 в 22:38

Общее среднее значение продукта

total_number_of_produts=`awk 'END{print NR}' filename`

awk -v t0="$total_number_of_produts" 'BEGIN{sum=0}{sum=sum+$NF}END{print sum/t0}' filename

output
1.777 (1.78)

Молочный продукт в среднем

da=`awk '/dairy/{print NR}' filename | wc -l`

awk -v t0="$total_number_of_produts" 'BEGIN{sum=0}{sum=sum+$NF}END{print sum/t0}' filename 


output
2.5
0
Praveen Kumar BS 9 Ноя 2019 в 10:43
Чтобы не повторять файл дважды, обратите внимание, как другие респонденты использовали sum/NR в своем блоке END для получения среднего значения.
 – 
Jeff Schaller
9 Ноя 2019 в 15:04
Конечно улучшится
 – 
Praveen Kumar BS
9 Ноя 2019 в 18:06
Когда вы редактируете пост, обязательно уточните, чем ваш подход отличается от трех других, потому что на первый взгляд он очень похож. Спасибо!
 – 
Jeff Schaller
9 Ноя 2019 в 22:02

Поскольку ОП попросил некоторых объяснений, вот попытка сделать это. Ответ основан на ответе Романа Перехреста, но немного отличается.

#!/bin/awk -f

{ 
    products = $2 # Store the second field in products
    a[products] += $NF # Increment each item in the array. $NF denotes the last field. 
    total += $NF # This is the total count of the last field all together resulting in a total of:  12.45
    pr[products]++  #increment by 1 if item found in second field. For dairy this should be 3
} 
END { 
    for (products in a)  # for loop
      print products, a[products] / pr[products]  # print product name, total of products / products found
      printf("All avg: %.2f\n", total/NR); # Print average of all products. So 12.45 / 7 = 1.778571
}

Вызовите скрипт следующим образом:

chmod u+x myawkscript.awk && ./myawkscript.awk inputfile 
0
Valentin Bajrami 7 Ноя 2019 в 23:03