#unix #awk
#unix #awk
Вопрос:
Я новичок в AWK. Я только что узнал, что встроен в переменную и цикл for. И из руководств я узнал, что NF означает количество полей в записи.. Я использовал его для подсчета количества полей в каждой записи базы данных, как показано ниже.
Имя базы данных: студент
Annie 101 56 89
Joy 102 78 56
rinken 103 45
и выполните над ним следующий код
awk '{print NR,"->",NF}' student
таким образом, он выдает вывод, как показано ниже..
1 -> 4
2 -> 4
3 -> 3
так что ясно, что это работает на местах..
Но в базе данных ниже это работает по-другому
Имя базы данных : практика
1
2
3
4
5
я выполнил следующую команду на нем, чтобы суммировать все данные
awk '{for(i=1;i<=NF;i ) total=total $i}; END {print total} ' practice
вывод :
15
итак, как работает NF во втором примере. Итак, мой вопрос заключается в том, как он вычисляет выходные данные, потому что существует только одно поле. итак, сколько раз цикл будет работать?
Комментарии:
1. поскольку в последнем примере на запись приходится только одно поле, цикл будет выполняться только один раз на строку ввода. Если бы у вас было больше полей, он бы перебирал их все
2. Я уверен, что если вы временно измените свой цикл на be
{for(i=1;i<=NF;i ) {print NR,NF,i,total; total=total $i}}
, вы ясно увидите, что происходит.
Ответ №1:
awk
выполняется последовательно для каждой строки, поэтому для каждой строки, которую он анализирует, он перебирает общее количество столбцов, которые находятся 1
в каждой строке.
Поэтому в идеале он анализирует как,
awk '{for(i=1;i<=NF;i ) total=total $i}; END {print total} ' practice
# value of i=1,NF=1 total=0 1 (1) NR=1
# value of i=1,NF=1 total=1 2 (3) NR=2
# value of i=1,NF=1 total=3 3 (6) NR=3
# value of i=1,NF=1 total=6 4 (10) NR=4
# value of i=1,NF=1 total=10 5 (15) NR=5
И чтобы суммировать все записи столбца 1
вместе, вы можете просто сделать
awk '{ sum = $1 } END { print sum }'
Ответ №2:
Этот for
цикл бесполезен в этом скрипте, поскольку в каждой записи есть только одно поле, плюс выходные данные никоим образом не связаны с NF
. Вы могли бы написать этот скрипт следующим образом:
awk '{total=total $1} END {print total}' practice
15
Ответ №3:
awk считывает каждый файл последовательно;
user@host:/tmp/test$ awk '{for(i=1;i<=NF;i ) total=total $i}; {printf "NumberOfRow : %s tNumberOfField : %s ttotal : %sn" , NR, NF, total } END {print "total sum : " total} ' practice
NumberOfRow : 1 NumberOfField : 1 total : 1
NumberOfRow : 2 NumberOfField : 1 total : 3
NumberOfRow : 3 NumberOfField : 1 total : 6
NumberOfRow : 4 NumberOfField : 1 total : 10
NumberOfRow : 5 NumberOfField : 1 total : 15
total sum : 15
Ответ №4:
Как работает цикл, даже если есть одно поле, так это то, что это (почти) правильная часть логики, которая работает в случае, когда есть поля, одно поле или два или более полей.
Переменная цикла i
инициализируется значением 1. Выражение защиты цикла является i <= NF
.
Таким образом, во-первых, если нет полей ( NF == 0
), цикл не будет выполняться, и в него ничего не будет добавлено total
.
Если есть одно поле, то выражение i<=NF
эквивалентно i<=1
, что является истинным, поэтому выполняется тело. Внутри тела цикла значение выражения $i
добавляется к total
. $
это специальный оператор Awk для индексации по полям. Поскольку i
равно 1, $i
эквивалентно $1
: ссылка на поле 1, поэтому поле 1 добавляется к итогу. Затем i
увеличивается на i
, становясь 2. Сбой i<=NF
защиты цикла, и поэтому цикл больше не выполняется.
Циклы могут выполняться ноль раз или только один раз.
Одна из проблем с кодом заключается в том, что если в файле вообще нет полей, программа не будет выдавать 0. total
Переменная остается неопределенной, и при ссылке print
в END
блоке in она выдает пробел.