Możesz zastosować różne podejścia w zależności od tego, czy awktraktuje się RSjako pojedynczy znak (jak awkrobią to tradycyjne implementacje), czy jako wyrażenie regularne (jak gawklub mawkrobią). Puste pliki są również trudne do rozważenia, ponieważ awkzwykle je pomijają.
gawk, mawkLub inne awkimplementacje, gdzie RSmoże być wyrażeniem regularnym.
W tych implementacjach (na przykład mawk, uważaj, że niektóre systemy operacyjne, takie jak Debian, dostarczają bardzo starą wersję zamiast nowoczesnej obsługiwanej przez @ThomasDickey ), jeśli RSzawiera pojedynczy znak, separatorem rekordów jest ten znak lub awkwchodzi w tryb akapitowy, gdy RSjest pusty, lub inaczej traktuje RSjako wyrażenie regularne.
Rozwiązaniem jest użycie wyrażenia regularnego, którego nie można dopasować. Niektórzy przychodzą na myśl jak x^lub $x( xprzed rozpoczęciem lub po zakończeniu). Jednak niektóre (szczególnie z gawk) są droższe niż inne. Jak dotąd uważam, że ^$jest to najbardziej wydajny. Można dopasować tylko przy pustym wejściu, ale wtedy nie byłoby nic, z czym można by się dopasować.
Więc możemy zrobić:
awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
Jedynym zastrzeżeniem jest to, że pomija puste pliki (w przeciwieństwie do perl -0777 -n). Można to rozwiązać za pomocą GNU awk, umieszczając kod w ENDFILEinstrukcji. Ale musimy również zresetować $0w instrukcji BEGINFILE, ponieważ w przeciwnym razie nie zostałby zresetowany po przetworzeniu pustego pliku:
gawk -v RS='^$' '
BEGINFILE{$0 = ""}
ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
tradycyjne awkwdrożenia, POSIXawk
W nich RSjest tylko jeden znak, nie mają BEGINFILE/ ENDFILE, nie mają RTzmiennej, ogólnie też nie mogą przetwarzać znaku NUL.
Można by pomyśleć, że użycie RS='\0'może wtedy działać, ponieważ i tak nie mogą przetwarzać danych wejściowych zawierających bajt NUL, ale nie, że RS='\0'w tradycyjnych implementacjach jest traktowane jako RS=tryb akapitowy.
Jednym z rozwiązań może być użycie znaku, który prawdopodobnie nie znajdzie się w danych wejściowych, takich jak \1. W lokalizacjach znaków wielobajtowych możesz nawet sprawić, że sekwencje bajtów będą bardzo mało prawdopodobne, ponieważ tworzą one znaki, które nie są przypisane lub znaki inne niż $'\U10FFFE'w ustawieniach regionalnych UTF-8. Nie bardzo niezawodny i masz również problem z pustymi plikami.
Innym rozwiązaniem może być przechowywanie całego wejścia w zmiennej i przetwarzanie go w instrukcji END na końcu. Oznacza to jednak, że możesz przetwarzać tylko jeden plik na raz:
awk '{content = content $0 RS}
END{$0 = content
printf "%s: <%s>\n", FILENAME, $0
}' file
To odpowiednik sed:
sed '
:1
$!{
N;b1
}
...' file1
Kolejny problem z tym podejściem jest to, że jeśli plik nie kończy się znakiem nowej linii (i nie była pusta), jeden jest wciąż arbitralnie dodane $0na końcu (z gawk, można obejść, że stosując RTzamiast RSw kod powyżej). Jedną z zalet jest to, że masz rekord liczby linii w pliku w NR/ FNR.