Вы можете использовать разные подходы в зависимости от того, awk
обрабатывает ли RS
он один символ (как awk
это делают традиционные реализации) или как регулярное выражение (как gawk
или mawk
делает). Пустые файлы также сложны, чтобы их можно 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
реализации, POSIXawk
В них 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
's:
sed '
:1
$!{
N;b1
}
...' file1
Еще одна проблема с этим подходом является то , что , если файл не заканчивается символом перевода строки (а не пустой), один по - прежнему произвольно добавляют $0
в конце (с gawk
, вы бы работать вокруг этого, используя RT
вместо того , чтобы RS
в код выше). Одним из преимуществ является то, что у вас есть запись о количестве строк в файле в NR
/ FNR
.