Вот, пожалуйста, один проход шаг awk решение -
awk 'NR==FNR{a = a + $2;next} {c = ($2/a)*100;print $1,$2,c }' file file
[jaypal:~/Temp] cat file
1 10
2 10
3 20
4 40
[jaypal:~/Temp] awk 'NR==FNR{a = a + $2;next} {c = ($2/a)*100;print $1,$2,c }' file file
1 10 12.5
2 10 12.5
3 20 25
4 40 50
Обновление: Если при выводе требуется табуляция, просто установите переменную OFS в "\ t".
[jaypal:~/Temp] awk -v OFS="\t" 'NR==FNR{a = a + $2;next} {c = ($2/a)*100;print $1,$2,c }' file file
1 10 12.5
2 10 12.5
3 20 25
4 40 50
Прорыв операторов типа {действие}:
Первый шаблон NR==FNR
. FNR - встроенная переменная awk, которая отслеживает количество записей (по умолчанию разделенных новой строкой) в данном файле. Таким образом, FNR в нашем случае будет 4. NR похож на FNR, но не сбрасывается до 0. Он продолжает расти. Таким образом, NR в нашем случае будет 8.
Этот шаблон будет верен только для первых 4 записей, и это именно то, что мы хотим. Изучив 4 записи, мы присваиваем сумму переменной a
. Обратите внимание, что мы не инициализировали его. В awk
нам не нужно. Однако это сломало бы, если весь столбец 2 равен 0. Таким образом, вы можете справиться с этим, поместив оператор if во второй оператор действия, т. Е. Выполнить деление, только если a> 0 еще скажет деление на 0 или что-то еще.
next
необходим, потому что мы не хотим, чтобы выполнялся второй оператор pattern {action}. next
говорит awk прекратить дальнейшие действия и перейти к следующей записи.
Как только четыре записи проанализированы, начинается следующий шаблон {действие}, который довольно прост. Делаем проценты и печатаем колонки 1 и 2 вместе с процентами рядом с ними.
Примечание: Как упомянуто в комментарии @lhf, эта однострочная строка будет работать, только если у вас есть набор данных в файле. Это не будет работать, если вы передадите данные по каналу.
В комментариях идет обсуждение способов заставить awk one-liner
принимать данные от pipe
вместо file
. Ну, единственный способ, которым я мог придумать, это сохранить значения столбцов в array
и затем использовать for loop
, чтобы выплевывать каждое значение вместе с их процентом.
Теперь arrays
в awk
равны associative
и никогда не в порядке, т. Е. Извлечение значений из массивов будет не в том порядке, в котором они вошли. Так что если все в порядке, то следующий лайнер должен работать.
[jaypal:~/Temp] cat file
1 10
2 10
3 20
4 40
[jaypal:~/Temp] cat file | awk '{b[$1]=$2;sum=sum+$2} END{for (i in b) print i,b[i],(b[i]/sum)*100}'
2 10 12.5
3 20 25
4 40 50
1 10 12.5
Чтобы привести их в порядок, вы можете передать результат в sort
.
[jaypal:~/Temp] cat file | awk '{b[$1]=$2;sum=sum+$2} END{for (i in b) print i,b[i],(b[i]/sum)*100}' | sort -n
1 10 12.5
2 10 12.5
3 20 25
4 40 50