awk встроенная переменная NF

#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 она выдает пробел.