È possibile adottare approcci diversi a seconda che si awktratti RSdi un singolo carattere (come awkfanno le implementazioni tradizionali ) o di un'espressione regolare (simile gawko simile mawk). Anche i file vuoti sono difficili da considerare perché awktendono a saltarli.
gawk, mawkO altre awkimplementazioni in cui RSpossono essere un espressione regolare.
In quelle implementazioni (per mawk, attenzione che alcuni sistemi operativi come Debian forniscono una versione molto vecchia invece di quella moderna gestita da @ThomasDickey ), se RScontiene un singolo carattere, il separatore di record è quel personaggio o awkentra nella modalità paragrafo quando RSè vuoto, o considera RSaltrimenti un'espressione regolare.
La soluzione è quella di utilizzare un'espressione regolare che non può essere abbinata. Alcuni vengono in mente come x^o $x( xprima dell'inizio o dopo la fine). Tuttavia alcuni (in particolare con gawk) sono più costosi di altri. Finora ho scoperto che ^$è il più efficiente. Può corrispondere solo su un input vuoto, ma non ci sarebbe nulla con cui confrontarsi.
Quindi possiamo fare:
awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
Un avvertimento però è che salta i file vuoti (contrariamente a perl -0777 -n). Ciò può essere risolto con GNU awkinserendo invece il codice in ENDFILEun'istruzione. Ma dobbiamo anche ripristinare $0in un'istruzione BEGINFILE in quanto altrimenti non verrebbe ripristinato dopo l'elaborazione di un file vuoto:
gawk -v RS='^$' '
BEGINFILE{$0 = ""}
ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
awkimplementazioni tradizionali , POSIXawk
In quelli, RSè solo un personaggio, non hanno BEGINFILE/ ENDFILE, non hanno la RTvariabile, inoltre generalmente non possono elaborare il carattere NUL.
Si potrebbe pensare che l'utilizzo RS='\0'possa funzionare, dato che comunque non possono elaborare input che contiene il byte NUL, ma no, che RS='\0'nelle implementazioni tradizionali viene trattato come RS=, che è la modalità paragrafo.
Una soluzione può essere quella di utilizzare un personaggio che difficilmente si trova nell'input come \1. Nelle localizzazioni di caratteri multibyte, puoi persino renderle sequenze di byte che è molto improbabile che si verifichino poiché formano caratteri che non sono assegnati o non caratteri come $'\U10FFFE'nelle localizzazioni UTF-8. Non è assolutamente infallibile e hai anche un problema con i file vuoti.
Un'altra soluzione può essere quella di memorizzare l'intero input in una variabile e di elaborarlo nell'istruzione END alla fine. Ciò significa che è possibile elaborare solo un file alla volta:
awk '{content = content $0 RS}
END{$0 = content
printf "%s: <%s>\n", FILENAME, $0
}' file
Questo è l'equivalente di sed:
sed '
:1
$!{
N;b1
}
...' file1
Un altro problema con questo approccio è che se il file non terminava con un carattere di nuova riga (e non era vuoto), $0alla fine ne viene aggiunto uno arbitrariamente (con gawk, si aggira il problema usando RTinvece che RSnel codice sopra). Un vantaggio è che hai un record del numero di righe nel file in NR/ FNR.