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