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