Ошибка logrotate nginx в задании cron

Вы можете использовать разные подходы в зависимости от того, обрабатывает ли awk RS как один символ (как традиционный ] awk ) или как регулярное выражение (например, gawk или mawk do).Пустые файлы также сложно рассматривать, поскольку awk имеет тенденцию пропускать их.

gawk , mawk или другие реализации awk , где RS может быть регулярным выражением.

В этих реализациях (для mawk помните, что некоторые операционные системы, такие как Debian, поставляют очень старую версию вместо современной, поддерживаемой @ThomasDickey ), если RS содержит один символ, разделителем записи является этот символ, или awk переходит в режим абзаца, когда RS пуст, или обрабатывает RS как регулярное выражение иначе.

Решение состоит в том, чтобы использовать регулярное выражение, которое невозможно сопоставить. На ум приходят такие, как x ^ или $ x ( x до начала или после конца). Однако некоторые (особенно с gawk ) дороже других. Пока что я обнаружил, что ^ $ является наиболее эффективным. Он может совпадать только с пустым вводом, но тогда не будет ничего, с чем сравнивать.

Итак, мы можем сделать:

awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...

Одно предостережение заключается в том, что он пропускает пустые файлы (в отличие от perl -0777 -n ). Это можно решить с помощью GNU awk , поместив вместо этого код в оператор ENDFILE .Но нам также необходимо сбросить $ 0 в операторе BEGINFILE, поскольку в противном случае он не будет сброшен после обработки пустого файла:

gawk -v RS='^$' '
   BEGINFILE{$0 = ""}
   ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...

традиционные реализации awk , POSIX awk

] В них RS - это всего лишь один символ, у них нет BEGINFILE / ENDFILE , у них нет RT переменная, они также обычно не могут обрабатывать символ NUL.

Можно подумать, что использование RS = '\ 0' может тогда работать, поскольку в любом случае они не могут обрабатывать ввод, содержащий байт NUL, но нет, это RS = '\ 0' в традиционных реализациях обрабатывается как RS = , что является режимом абзаца.

Одним из решений может быть использование символа, который вряд ли будет найден во входных данных, например \ 1 . В языковых стандартах многобайтовых символов вы даже можете сделать их последовательностями байтов, которые очень маловероятны, поскольку они образуют символы, которые не назначены или не являются символами, например $ '\ U10FFFE' в локали UTF-8. Однако это не совсем надежно, и у вас также есть проблема с пустыми файлами.

Другое решение может заключаться в том, чтобы сохранить весь ввод в переменной и обработать его в операторе END в конце.Это означает, что вы можете обрабатывать только один файл за раз:

awk '{content = content $0 RS}
     END{$0 = content
       printf "%s: <%s>\n", FILENAME, $0
     }' file

Это эквивалент sed :

sed '
  :1
  $!{
   N;b1
  }
  ...' file1

Другая проблема с этим подходом заключается в том, что если файл не заканчивался новой строкой (и не был пустым), один все еще произвольно добавляется в $ 0 в конце (с gawk , вы можете обойти это, используя RT вместо RS в приведенном выше коде). Одним из преимуществ является то, что у вас есть запись количества строк в файле в NR / FNR .

10
16.06.2015, 00:53
0 ответов

Теги

Похожие вопросы