Как обнаружить EOF в awk? - PullRequest
       103

Как обнаружить EOF в awk?

9 голосов
/ 30 октября 2009

Есть ли способ определить, является ли текущая строка последней строкой входного потока?

Ответы [ 11 ]

11 голосов
/ 30 октября 2009

Специальный шаблон END будет соответствовать только после окончания all input . Обратите внимание, что этот шаблон нельзя комбинировать с любым другим шаблоном.

Более полезной, вероятно, является псевдофункция getline, которая сбрасывает $0 на следующую строку и возвращает 1, а в случае EOF возвращает 0! Что я думаю, что вы хотите.

Например:

awk '{ if(getline == 0) { print "Found EOF"} }'

Если вы обрабатываете только один файл, это будет эквивалентно:

awk 'END { print "Found EOF" }'
8 голосов
/ 30 октября 2009

У вас есть два варианта, оба типа грязные.

  1. Сохраните копию каждой текущей строки во временной переменной, а затем используйте блок END для ее обработки.
  2. Используйте системную команду для запуска «wc -l | getline» в блоке BEGIN, чтобы получить количество строк в файле, а затем подсчитать это значение.

Возможно, вам придется немного поиграть с # 2, чтобы он заработал, но он должен работать. Прошло много времени с тех пор, как я сделал какой-либо awk.

6 голосов
/ 13 декабря 2012

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

awk 'NR==FNR{max++; next} FNR == max { print "Final line:",$0 }' file file

awk -v max="$(wc -l < file)" 'FNR == max { print "Final line:",$0 }' file

awk 'BEGIN{ while ( (getline dummy < ARGV[1]) > 0) max++; close(ARGV[1])} FNR == max { print "Final line:",$0 }' file
4 голосов
/ 19 февраля 2014

Обнаружение EOF не слишком надежно, когда в командной строке находится несколько файлов. Обнаружение начала файла является более надежным.

Для этого первый файл особенный, и мы игнорируем FNR == 1.

После первого файла FNR == 1 становится концом предыдущего файла. У last_filename всегда есть имя файла, который вы обрабатываете.

Выполните обработку вашего файла после остального.

Выполните обработку EOF внутри блока else и в блоке END.

   gawk 'BEGIN{last_filename="";} \
      FNR==1{if (last_filename==""){last_filename=FILENAME;} \
      else {print "EOF: "last_filename;last_filename=FILENAME;}} \
      END{print "END: "last_filename;}' $*

Для нескольких наборов файлов блок else выполняется в EOF для всех, кроме последнего файла. Последний файл выполняется в блоке END.

Для отдельных наборов файлов блок else не выполняется, а блок END выполняется.

2 голосов
/ 13 октября 2016
Реализация

gawk имеет специальное правило под названием ENDFILE, которое будет запускаться после обработки каждого файла в списке аргументов. Это работает:

awk '{line=$0} ENDFILE {print line}' files...

подробнее вы можете найти здесь >>

2 голосов
/ 05 ноября 2009

Я даже не уверен, как классифицировать это "решение"

{
    t = lastline
    lastline = $0
    $0 = t
}

/test/ {
    print "line <" $0 "> had a _test_"
}

END {
    # now you have "lastline", it can't be processed with the above statements
    # ...but you can work with it here
}

Крутая вещь в этом хаке заключается в том, что, присваивая $0, все оставшиеся декларативные шаблоны и действия работают, одна строка задерживается. Вы не можете заставить их работать на END, даже если вы поставите END сверху, но у вас есть контроль над последней строкой, и вы больше ничего с ним не сделали .

1 голос
/ 06 декабря 2011

Один простой способ - запустить файл с помощью промежуточного сценария sed, который помещает 0 в каждую не последнюю строку и 1 в последнюю.

cat input_file | sed 's/^/0/;$s/0/1/' | awk '{LST=/^1/;$0=substr($0,2)}
... your awk script in which you can use LST to check for the
... last line.'
1 голос
/ 09 сентября 2010

Для определения последней строки каждого файла в списке аргументов хорошо работает следующее:

FNR == 1 || EOF {
  print "last line (" FILENAME "): " $0
}
0 голосов
/ 02 января 2018

Переносное решение представлено в руководстве пользователя gawk , хотя, как уже упоминалось в другом ответе, само gawk имеет BEGINFILE и ENDFILE.

0 голосов
/ 18 февраля 2016

Вы можете попробовать это:

awk 'BEGIN{PFNR=1} FNR==PFNR{PFNR++;next} {print FILENAME,PFNR=2} END{print FILENAME}' file1 file2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...