Bu sorunun yorumlarında, çeşitli sed uygulamalarının oldukça basit bir programa katılmadığı bir durum ortaya çıktı ve biz (veya en azından ben) spesifikasyonun aslında bunun için ne gerektirdiğini belirleyemedik.
Sorun, silinen bir satırdan başlayan bir aralığın davranışıdır:
1d;1,2d
Bu komuta ulaşmadan önce aralığın başlangıcı kaldırılmış olsa bile 2. satır silinmeli mi? İlk beklentim BSD sed ile "hayır" iken, GNU sed "evet" diyor ve şartname metnini kontrol etmek sorunu tamamen çözmüyor.
Beklentilerimi karşılayan (en azından) macOS ve Solaris sed
ve BSD sed
. Katılmama (en azından) GNU ve Busybox sed
ve burada çok sayıda insan var. İlk ikisi SUS sertifikalı, diğerleri ise daha yaygın. Hangi davranış doğrudur?
Şartname metni iki adres aralıkları için şöyle diyor:
Sed Komut sonraki döngüsü veya sonlandırılıyor başlayıncaya kadar yarar, sonra sırası Adresleri örüntü alanı seçmek tüm komutlar geçerli olacaktır.
ve
İki adresli bir düzenleme komutu, ilk adresle eşleşen ilk desen alanından ikinciyle eşleşen bir sonraki desen alanına dahil olan aralığı seçmelidir. [...] Seçilen aralığı takip eden ilk satırdan başlayarak, sed ilk adresi arar. Daha sonra işlem tekrarlanacaktır.
Muhtemelen, satır 2 olduğu içinde bakılmaksızın başlangıç noktası silinmiştir bakılmaksızın, "ikinci maçları sonraki model uzayda ilk adresiyle eşleşen ilk desen uzaydan dahil aralık". Öte yandan, ilkinin bir d
sonraki döngüye geçmesini ve aralığa başlama şansı vermemesini bekledim . UNIX ™ sertifikalı uygulamalar beklediğim şeyi yapıyor ancak potansiyel olarak şartnamenin zorunlu kıldığı şeyleri yapmıyor.
Bazı açıklayıcı deneyler takip eder, ancak kilit soru şudur: bir aralık silinen bir satırda başladığında ne yapmalı sed
?
Deneyler ve örnekler
Sorunun basitleştirilmiş bir gösterimi, satırları silmek yerine fazladan kopyalar basan şudur:
printf 'a\nb\n' | sed -e '1d;1,2p'
Bu, sed
iki satır giriş sağlar a
ve b
. Program iki şey yapar:
İle ilk satırı siler
1d
.d
komut olacakDesen alanını silin ve bir sonraki döngüyü başlatın. ve
- Her satırın otomatik olarak yazdırılmasına ek olarak, 1 ila 2 arasındaki satır aralığını seçin ve bunları açıkça yazdırın. Böylece aralığa dahil edilen bir çizgi iki kez görünmelidir.
Benim beklentim bunun yazdırılması gerektiğiydi
b
yalnızca, uygulama aralığı kullanılmadığı için 1,2
, satır 1 sırasında hiçbir zaman ulaşılmadığı için ( d
zaten bir sonraki döngüye / satıra atlandığı için) ve böylece aralık dahil etme işlemi asla a
silinmezken başlamaz . sed
MacOS ve Solaris 10'un uyumlu Unix'leri , genel olarak sed
Solaris ve BSD'de POSIX olmayanlar gibi bu çıktıyı üretir sed
.
Diğer yandan GNU sed
b
b
bu işaret etti aralığı yorumlanır. Bu hem POSIX modunda gerçekleşir, hem de olmaz. Busybox'ın sed aynı davranışa sahiptir (ancak her zaman aynı davranış değildir, bu nedenle paylaşılan kodun bir sonucu değildir).
İle daha fazla deney
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'
silinmiş bir satırdan başlayarak bir aralığı bir sonraki satırdan başlıyormuş gibi görür . Bu /c/
aralık görünür çünkü aralığın sonunu getirmiyor. Kullanılması /b/
aralığını başlatmak için yok değil aynı davranırlar 2
.
Kullandığım ilk çalışma örneği
printf '%s\n' a b c d e | sed -e '1{/a/d;};1,//d'
ilk /a/
hatta kadar olan tüm satırları silmenin bir yolu olarak , bu ilk satırda olsa bile (GNU sed'in ne kullanacağı 0,/a/d
- bu POSIX uyumlu bir yorumlama girişimiydi).
Yerine kadar silmelisiniz ileri sürülmüştür ikinci maç /a/
mantıklı görünüyor, ilk satır maçları (hayır ikinci eşleşme veya tüm dosya ise) eğer - ama yine sadece GNU bunu yapmaz sed. Hem macOS sed hem de Solaris'in sed üretimi
b
c
d
e
bunun için, beklediğim gibi (GNU sed boş çıktıyı sonlandırılmamış aralığı kaldırmaktan üretir; Busybox sed sadece yazdırır d
ve e
ne olursa olsun açıkça yanlıştır). Genellikle sertifikasyon uygunluk testlerini geçtiklerini, davranışlarının doğru olduğu anlamına gelir, ancak yeterli sayıda insan başka türlü emin olmadığımı önerdi, şartname metni tamamen ikna edici değil ve test takımı olamaz mükemmel kapsamlı.
Açıkçası, bu tutarsızlık nedeniyle bugün bu kodu yazmak pratik olarak taşınabilir değildir, ancak teorik olarak her yerde bir anlam veya diğeri ile eşdeğer olmalıdır. Bunun bir hata olduğunu düşünüyorum, ancak hangi uygulama (lar) ı bildireceğini bilmiyorum. Şu anda benim görüşüme göre GNU ve Busybox sed'in davranışı şartname ile tutarsız, ama bu konuda yanılmış olabilirim.
POSIX burada ne gerektirir?
ed
,sed
tamamen atlayarak ?