Anda dapat mengambil pendekatan berbeda tergantung pada apakah awk
memperlakukan RS
sebagai karakter tunggal (seperti awk
implementasi tradisional lakukan) atau sebagai ekspresi reguler (suka gawk
atau mawk
tidak). File kosong juga rumit untuk dipertimbangkan karena awk
cenderung melompati mereka.
gawk
, mawk
atau awk
implementasi lain di mana RS
bisa menjadi regexp.
Dalam implementasi tersebut (untuk mawk
, berhati-hatilah bahwa beberapa OS seperti Debian mengirimkan versi yang sangat lama dan bukan versi modern yang dikelola oleh @ThomasDickey ), jika RS
berisi satu karakter, pemisah rekaman adalah karakter itu, atau awk
memasuki mode paragraf ketika RS
kosong, atau memperlakukan RS
sebagai ekspresi reguler jika tidak.
Solusinya adalah menggunakan ekspresi reguler yang tidak mungkin dapat dicocokkan. Beberapa muncul di pikiran seperti x^
atau $x
( x
sebelum memulai, atau setelah akhir). Namun beberapa (terutama dengan gawk
) lebih mahal daripada yang lain. Sejauh ini, saya telah menemukan itu ^$
yang paling efisien. Itu hanya bisa cocok dengan input kosong, tetapi kemudian tidak akan ada yang cocok dengan.
Jadi kita bisa melakukan:
awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
Satu peringatan adalah bahwa ia melewatkan file kosong (bertentangan dengan perl -0777 -n
). Itu bisa diatasi dengan GNU awk
dengan memasukkan kode dalam ENDFILE
pernyataan sebagai gantinya. Tetapi kita juga perlu mengatur ulang $0
dalam pernyataan BEGINFILE karena jika tidak maka tidak akan diatur ulang setelah memproses file kosong:
gawk -v RS='^$' '
BEGINFILE{$0 = ""}
ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
awk
implementasi tradisional , POSIXawk
Pada mereka, RS
hanya satu karakter, mereka tidak memiliki BEGINFILE
/ ENDFILE
, mereka tidak memiliki RT
variabel, mereka juga umumnya tidak dapat memproses karakter NUL.
Anda akan berpikir bahwa menggunakan RS='\0'
bisa bekerja maka karena bagaimanapun mereka tidak dapat memproses input yang berisi byte NUL, tetapi tidak, yang RS='\0'
dalam implementasi tradisional diperlakukan sebagai RS=
, yang merupakan mode paragraf.
Salah satu solusinya adalah menggunakan karakter yang tidak mungkin ditemukan di input seperti \1
. Di lokal karakter multibyte, Anda bahkan dapat membuatnya byte-sequence yang sangat tidak mungkin terjadi karena mereka membentuk karakter yang tidak ditugaskan atau non-karakter seperti $'\U10FFFE'
di lokal UTF-8. Tidak terlalu mudah dan Anda memiliki masalah dengan file kosong juga.
Solusi lain dapat menyimpan seluruh input dalam suatu variabel dan memprosesnya dalam pernyataan AKHIR di bagian akhir. Itu berarti Anda hanya dapat memproses satu file pada satu waktu:
awk '{content = content $0 RS}
END{$0 = content
printf "%s: <%s>\n", FILENAME, $0
}' file
Itu setara sed
dengan:
sed '
:1
$!{
N;b1
}
...' file1
Masalah lain dengan pendekatan itu adalah bahwa jika file tidak berakhir dengan karakter baris baru (dan tidak kosong), orang masih secara sewenang-wenang ditambahkan di $0
akhir (dengan gawk
, Anda akan mengatasinya dengan menggunakan RT
alih-alih RS
di kode di atas). Satu keuntungan adalah bahwa Anda memiliki catatan jumlah baris dalam file di NR
/ FNR
.