Vous pouvez prendre différentes approches selon que awktraite RScomme un seul caractère (comme traditionnelles awkmises en œuvre font) ou comme une expression régulière (comme gawkou mawkfaire). Les fichiers vides sont également difficiles à considérer car ils ont awktendance à les ignorer.
gawk, mawkou d'autres awkimplémentations où RSpeut être une expression rationnelle.
Dans ces implémentations ( mawksachez que certains systèmes d'exploitation comme Debian livrent une version très ancienne au lieu de la version moderne maintenue par @ThomasDickey ), s'il RScontient un seul caractère, le séparateur d'enregistrement est ce caractère, ou awkpasse en mode paragraphe lorsqu'il RSest vide, ou traite RScomme une expression régulière dans le cas contraire.
La solution consiste à utiliser une expression régulière qui ne peut pas correspondre. Certains viennent à l'esprit comme x^ou $x( xavant le début ou après la fin). Cependant, certains (en particulier avec gawk) sont plus chers que d'autres. Jusqu'à présent, j'ai trouvé que ^$c'était le plus efficace. Il ne peut correspondre qu'à une entrée vide, mais il n'y aurait alors rien à comparer.
On peut donc faire:
awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
Une mise en garde est cependant qu'il saute les fichiers vides (contrairement à perl -0777 -n). Cela peut être résolu avec GNU awken mettant le code dans une ENDFILEinstruction à la place. Mais nous devons également réinitialiser $0dans une instruction BEGINFILE car elle ne serait pas autrement réinitialisée après le traitement d'un fichier vide:
gawk -v RS='^$' '
BEGINFILE{$0 = ""}
ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
awkimplémentations traditionnelles , POSIXawk
Dans ceux-ci, il RSn'y a qu'un seul caractère, ils n'ont pas BEGINFILE/ ENDFILE, ils n'ont pas la RTvariable, ils ne peuvent généralement pas non plus traiter le caractère NUL.
On pourrait penser que l'utilisation RS='\0'pourrait fonctionner alors car de toute façon ils ne peuvent pas traiter l'entrée qui contient l'octet NUL, mais non, celle RS='\0'dans les implémentations traditionnelles est traitée comme RS=, qui est le mode paragraphe.
Une solution peut être d'utiliser un caractère qui ne se trouvera probablement pas dans l'entrée comme \1. Dans les paramètres régionaux de caractères multi-octets, vous pouvez même créer des séquences d'octets qui sont très peu susceptibles de se produire car ils forment des caractères qui ne sont pas affectés ou des caractères non comme $'\U10FFFE'dans les paramètres régionaux UTF-8. Pas vraiment infaillible et vous avez également un problème avec les fichiers vides.
Une autre solution peut être de stocker l'intégralité de l'entrée dans une variable et de la traiter dans l'instruction END à la fin. Cela signifie que vous ne pouvez traiter qu'un seul fichier à la fois:
awk '{content = content $0 RS}
END{$0 = content
printf "%s: <%s>\n", FILENAME, $0
}' file
C'est l'équivalent de sed:
sed '
:1
$!{
N;b1
}
...' file1
Un autre problème avec cette approche est que si le fichier ne se terminait pas par un caractère de nouvelle ligne (et n'était pas vide), un est toujours ajouté arbitrairement $0à la fin (avec gawk, vous contourneriez cela en utilisant RTau lieu de RSdans le code ci-dessus). Un avantage est que vous avez un enregistrement du nombre de lignes dans le fichier dans NR/ FNR.