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