Как `awk 'NF {p=1} p'` удаляет пустые строки из начала и конца файла?

Как `awk 'NF {p=1} p'` удаляет пустые строки из начала и конца файла?

В поисках способа удаления пустых строк в начале и конце tacфайла (с помощью ) я наткнулся на это:

awk 'NF {p=1} p'

Как/почему это работает?

Я понимаю NF, что это только trueесли есть какие-либо поля (если строка не пустая).

решение1

Это удалит пустые строки в начале,но не с концафайла.[Примечание: этот ответ был написан доправка к вопросучто упомянуто tac]

Работает это следующим образом:

  • NFколичество полей, найденных в текущей строке. Если оно равно нулю, это означает, что строка либо пустая, либопустой, т.е. содержит максимум пробелы (при условии, что разделитель полей оставлен в значении по умолчанию, где любое количество последовательных пробелов считается разделителем).
  • Текущая строка печатается, если любое условие вне (и не связанное с) блоков правил ( { ... }) оценивается как true. Флаг pизначально не инициализирован и будет оцениваться как false, поэтому априори ничего не будет напечатано.
  • Как только найдена непустая строка ( NFотлична от нуля и оценивается как true), блок правил {p=1}вводится, и флаг pустанавливается в 1. После этого pвнешняя часть блока правил оценивается как true, и все последующие строки (включая текущую, первую непустую) печатаются.

Уведомлениечто поскольку флаг pникогда не сбрасывается, любые пустые строки, следующие за первой непустой строкой, будут напечатаны без фильтрации. Если вы хотите удалить пустые строки и в конце, понадобится двухпроходный подход:

awk 'FNR==NR{if (NF) {if (!first) first=FNR; last=FNR} next}
     FNR>=first && FNR<=last' input.txt input.txt

Это обработает файл дважды (поэтому он указан дважды как операнд)

  • На первом проходе, где FNRсчетчик строк для каждого файла равен NRглобальному счетчику строк, мы определяем первую и последнюю непустую строку.
  • Во втором проходе ( FNRтеперь меньше, чем NR) мы печатаем только строки между (включая) идентифицированными первой и последней непустыми строками.

Уведомление

Как указано вответ Стефана Шазеля, двухпроходный подход работает только с обычными файлами. Если ваш ввод имеет иную природу, см. предложенный там метод для решения.

решение2

Использование этого метода для удаления пустых строк из начала и конца файла:

awk 'NF {p=1} p' file | # remove blank lines at the file head
  tac |                 # reverse the lines
  awk 'NF {p=1} p' |    # remove blanks from the "new head"
  tac |                 # re-reverse the file
  sponge file           # from the `moreutils` package, to overwrite the file

решение3

Что делает ваш код и почему он удаляет только пустые строки в начале ввода, уже объяснялось в@AdminBee ответнапример, но здесь для полноты картины я предложу альтернативный метод удаления как начальных, так и конечных пустых строк без необходимости делать два прохода по файлу (что будет работать только для обычных файлов, а не для произвольного ввода).

awk '
       NF {print saved $0; saved = ""; started = 1; next}
  started {saved = saved $0 ORS}' < file

Где мы задерживаем печать пустых строк до следующей непустой строки, которую видим после этого (при условии, что мы уже видели хотя бы одну непустую строку ранее).

решение4

Если вы не против удаления пробелов и табуляций в пустых строках, которые вы хотите сохранить, это удалит пустые строки в начале и конце:

awk 'NF{for(;c;--c)print "";print;x=1;next} x{++c}'

Он подсчитывает количество пустых строк между непустыми строками и выводит это количество пустых строк перед каждой непустой строкой.

Связанный контент