Вы можете использовать разные подходы в зависимости от того, 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.