Dalam komentar untuk pertanyaan ini muncul kasus di mana berbagai implementasi sed tidak setuju pada program yang cukup sederhana, dan kami (atau setidaknya saya) tidak dapat menentukan spesifikasi yang sebenarnya diperlukan untuk itu.
Masalahnya adalah perilaku rentang yang dimulai pada baris yang dihapus:
1d;1,2d
Haruskah baris 2 dihapus meskipun awal rentang telah dihapus sebelum mencapai perintah itu? Harapan awal saya adalah "tidak" sejalan dengan sed BSD, sementara GNU sed mengatakan "ya", dan memeriksa teks spesifikasi tidak sepenuhnya menyelesaikan masalah.
Sesuai harapan saya adalah (setidaknya) macOS dan Solaris sed
, dan BSD sed
. Yang tidak setuju adalah (setidaknya) GNU dan Busybox sed
, dan banyak orang di sini. Dua yang pertama bersertifikat SUS sementara yang lain lebih luas. Perilaku mana yang benar?
The spesifikasi teks untuk rentang dua alamat mengatakan:
The sed utilitas kemudian berlaku secara berurutan semua perintah yang alamat pilih ruang yang pola, sampai perintah mulai siklus berikutnya atau berhenti.
dan
Perintah pengeditan dengan dua alamat harus memilih rentang inklusif dari ruang pola pertama yang cocok dengan alamat pertama melalui ruang pola berikutnya yang cocok dengan yang kedua. [...] Mulai dari baris pertama mengikuti rentang yang dipilih, sed akan mencari lagi untuk alamat pertama. Setelah itu, proses harus diulang.
Dapat diperdebatkan, baris 2 berada dalam "rentang inklusif dari ruang pola pertama yang cocok dengan alamat pertama melalui ruang pola berikutnya yang cocok dengan yang kedua", terlepas dari apakah titik awal telah dihapus. Di sisi lain, saya mengharapkan yang pertama d
untuk melanjutkan ke siklus berikutnya dan tidak memberikan rentang kesempatan untuk memulai. Implementasi bersertifikasi UNIX ™ melakukan apa yang saya harapkan, tetapi berpotensi tidak sesuai dengan mandat spesifikasi.
Beberapa eksperimen ilustratif mengikuti, tetapi pertanyaan kuncinya adalah: apa yang harus sed
dilakukan ketika rentang dimulai pada baris yang dihapus?
Eksperimen dan contoh
Demonstrasi yang disederhanakan dari masalah ini adalah ini, yang mencetak salinan garis lebih banyak daripada menghapusnya:
printf 'a\nb\n' | sed -e '1d;1,2p'
Ini menyediakan sed
dua jalur input, a
dan b
. Program ini melakukan dua hal:
Menghapus baris pertama dengan
1d
. Thed
perintah akanHapus ruang pola dan mulai siklus berikutnya. dan
- Pilih rentang garis dari 1 hingga 2 dan cetak secara eksplisit, selain pencetakan otomatis yang diterima setiap baris. Garis yang termasuk dalam rentang dengan demikian akan muncul dua kali.
Harapan saya adalah ini harus dicetak
b
hanya, dengan rentang yang tidak berlaku karena 1,2
tidak pernah tercapai selama baris 1 (karena sudah d
melompat ke siklus / baris berikutnya) dan dengan demikian jangkauan inklusi tidak pernah dimulai, sementara a
telah dihapus. Unix sed
s dari macOS dan Solaris 10 menghasilkan output ini, seperti halnya non-POSIX sed
di Solaris dan BSD sed
secara umum.
GNU sed, di sisi lain, mencetak
b
b
menunjukkan bahwa ia telah menafsirkan kisaran. Ini terjadi baik dalam mode POSIX dan tidak. Busybox's sed memiliki perilaku yang sama (tetapi perilaku yang tidak selalu identik, sehingga sepertinya bukan hasil dari kode bersama).
Eksperimen lebih lanjut dengan
printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/c/p'
printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/d/p'
menemukan bahwa itu tampaknya memperlakukan rentang yang dimulai pada baris yang dihapus seolah-olah itu dimulai pada baris berikut . Ini terlihat karena /c/
tidak cocok untuk mengakhiri rentang. Menggunakan /b/
untuk memulai rentang tidak berperilaku sama dengan 2
.
Contoh kerja awal yang saya gunakan adalah
printf '%s\n' a b c d e | sed -e '1{/a/d;};1,//d'
sebagai cara untuk menghapus semua baris hingga /a/
pertandingan pertama , bahkan jika itu ada di baris pertama (apa yang akan digunakan oleh GNU 0,/a/d
- ini adalah percobaan yang kompatibel dengan POSIX untuk itu).
Disarankan bahwa ini seharusnya menghapus hingga kecocokan kedua/a/
jika baris pertama cocok (atau seluruh file jika tidak ada kecocokan kedua), yang tampaknya masuk akal - tetapi sekali lagi, hanya sed GNU yang melakukan itu. Baik sed macOS dan sed solaris
b
c
d
e
untuk itu, seperti yang saya perkirakan (GNU sed menghasilkan output kosong dari menghapus rentang yang tidak ditentukan; sed Busybox mencetak hanya d
dan e
, yang jelas salah apa pun). Secara umum saya akan berasumsi bahwa mereka telah lulus tes kesesuaian sertifikasi berarti bahwa perilaku mereka benar, tetapi cukup banyak orang menyarankan sebaliknya bahwa saya tidak yakin, teks spesifikasi tidak sepenuhnya meyakinkan, dan test suite tidak dapat sangat komprehensif.
Jelas itu tidak praktis portabel untuk menulis kode hari ini mengingat inkonsistensi, tetapi secara teoritis harus setara di mana-mana dengan satu makna atau yang lain. Saya pikir ini adalah bug, tapi saya tidak tahu implementasi mana yang harus dilaporkan. Pandangan saya saat ini adalah bahwa perilaku sed GNU dan Busybox tidak konsisten dengan spesifikasi, tapi saya bisa salah tentang itu.
Apa yang dibutuhkan POSIX di sini?
ed
, melewatised
semuanya?