Puede adoptar diferentes enfoques dependiendo de si se awk
trata RS
como un solo carácter (como lo hacen las awk
implementaciones tradicionales ) o como una expresión regular (como gawk
o mawk
hacer). Los archivos vacíos también son difíciles de considerar, ya que awk
tienden a omitirlos.
gawk
, mawk
U otras awk
implementaciones en las que RS
pueden ser una expresión regular.
En esas implementaciones (para mawk
, tenga en cuenta que algunos sistemas operativos como Debian envían una versión muy antigua en lugar de la moderna mantenida por @ThomasDickey ), si RS
contiene un solo carácter, el separador de registros es ese carácter o awk
ingresa al modo de párrafo cuando RS
está vacío, o trata RS
como una expresión regular de lo contrario.
La solución es usar una expresión regular que no se pueda igualar. Algunos vienen a la mente como x^
o $x
( x
antes del comienzo o después del final). Sin embargo, algunos (particularmente con gawk
) son más caros que otros. Hasta ahora, he encontrado que ^$
es el más eficiente. Solo puede coincidir con una entrada vacía, pero entonces no habría nada contra lo que comparar.
Entonces podemos hacer:
awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
Sin embargo, una advertencia es que omite archivos vacíos (al contrario de perl -0777 -n
). Eso se puede abordar con GNU awk
colocando el código en una ENDFILE
declaración. Pero también necesitamos restablecer $0
en una declaración BEGINFILE, ya que de lo contrario no se restablecería después de procesar un archivo vacío:
gawk -v RS='^$' '
BEGINFILE{$0 = ""}
ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
awk
implementaciones tradicionales , POSIXawk
En esos, RS
solo hay un personaje, no tienen BEGINFILE
/ ENDFILE
, no tienen la RT
variable, generalmente tampoco pueden procesar el carácter NUL.
Pensaría que usar RS='\0'
podría funcionar entonces, ya que de todos modos no pueden procesar la entrada que contiene el byte NUL, pero no, RS='\0'
en las implementaciones tradicionales se trata como RS=
, que es el modo de párrafo.
Una solución puede ser usar un carácter que es poco probable que se encuentre en la entrada como \1
. En las configuraciones regionales de caracteres multibyte, incluso puede crear secuencias de bytes que es muy poco probable que ocurran ya que forman caracteres que no están asignados o que no son caracteres como $'\U10FFFE'
en las configuraciones regionales UTF-8. Sin embargo, no es realmente infalible y también tiene un problema con los archivos vacíos.
Otra solución puede ser almacenar toda la entrada en una variable y procesarla en la instrucción END al final. Sin embargo, eso significa que solo puede procesar un archivo a la vez:
awk '{content = content $0 RS}
END{$0 = content
printf "%s: <%s>\n", FILENAME, $0
}' file
Eso es el equivalente de sed
's:
sed '
:1
$!{
N;b1
}
...' file1
Otro problema con ese enfoque es que si el archivo no terminaba en un carácter de nueva línea (y no estaba vacío), uno todavía se agrega arbitrariamente $0
al final (con gawk
, evitaría eso al usarlo en RT
lugar de RS
en el código de arriba). Una ventaja es que tiene un registro del número de líneas en el archivo en NR
/ FNR
.