Sed'de birden fazla ünlem işareti kullanmanın anlamı nedir?


12

POSIX sed belgeleri şunları söyledi:

Bir işlevden önce bir veya daha fazla '!' karakterler, bu durumda adresler desen boşluğunu seçmezse işlev uygulanacaktır. Sıfır veya daha fazla <boş> karakter ilk '!' karakter. <Boş> karakterlerin bir '!' karakteri ve uygun uygulamalar bir '!' boş karakter.

Yani, herhangi bir POSIX sed ile şunları yapabiliriz:

sed -e '/pattern/!d' file

Yazmakla aynı şey:

sed -e '/pattern/!!d' file

Ve !!!dve nünlem işaretleri hala (üç ile test edilmiştir cezası olacaksın sedgelen sürümü yadigarı ToolChest ). Bir ünlem yerine katlar arasında hiçbir fayda görmüyorum.

Spesifikasyon neden bu sözdizimine izin verdi ve gerçek dünya uygulamasında nasıl kullanışlı?


Görünüşe göre GNU sed bu durumda uyumlu değil, birden fazla ünlem kullanırsak şikayet edecek:

$ sed -e '/pattern/!!d' file
sed: -e expression #1, char 11: multiple `!'s

2
FWIW: OpenBSD'de !bir geçiş işlevi görür /pattern/!!, aynı /pattern/ve /pattern/!!!aynıdır /pattern/!. FreeBSD'de çoklu !, tekli ile aynıdır.
lcd047

2
Spesifikasyondaki birçok şeyin anlamı, sedkomut dosyalarının oluşturulabilmesidir . POSIX verildiğinde sed, bir sedkomut dosyasının yazımını yazmak gerçekten basit bir konu olmalıdır . Bu nedenle !, eyleminiz ne olursa olsun bir adresi işaretlemesi gereken bazı durumlar için tetikleyiciniz varsa , aynı şey için birden çok kez tetikleyebilir ve yine de aynı sonuçlarla çıkabilirsiniz.
mikeserv

@cuonglm Hayır, sadece FreeBSD'ler. GNU, OpenBSD ve NetBSD'ler seddeğildir.
lcd047

@ lcd047: evet, elbette. Kötü İngilizcem için özür dilerim. Yani uyumlu değil, değil mi? Bunu bilmek güzel. Ama sorumun ana noktası , sözdiziminin POSIX sed ile gerçek dünyada nasıl yararlı olabileceğidir?
cuonglm

1
FWIW: OpenBSD akımında bunun için bir düzeltme yapılmıştır.
lcd047

Yanıtlar:


5

sedadlı kullanıcının API'si ilkeldir - ve bu tasarım gereğidir. En azından, etti kalmıştır tasarımıyla ilkel - bu söyleyemem başlangıcında ilkel tasarlanmış olup olmadığı. Çoğu durumda, sedçalıştırıldığında başka bir sedkomut dosyası çıktısı yapacak bir komut dosyasının yazılması gerçekten basit bir konudur. ve / veya sedgibi makro ön işlemcileri tarafından bu şekilde uygulanır .m4make

(Aşağıdaki son derece varsayımsal bir kullanım örneğidir: bir çözüme uyacak şekilde tasarlanmış bir sorundur. Size bir gerginlik gibi geliyorsa, muhtemelen bunun nedeni budur, ancak bu daha az geçerli kılmaz.)


Aşağıdaki girdi dosyasını göz önünde bulundurun:

cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower

Yukarıdaki girdi dosyasındaki her uygun kelimenin kuyruğuna -casesed kelimesini ekleyecek bir komut dosyası yazmak isteseydik, ancak uygun bağlamda bir satırda bulunabilseydik ve bunu olabildiğince verimli yapmak istedik ( hedefimiz olması gerektiği gibi, örneğin bir derleme işlemi sırasında) o zaman regexp'leri mümkün olduğunca uygulamaktan kaçınmalıyız .//

Yapabileceğimiz bir şey şu anda sistemimizdeki dosyayı önceden düzenlemek ve sedderleme sırasında asla aramamaktır. Ancak, dosyadaki bu kelimelerden herhangi biri yerel ayarlara ve / veya derleme zamanı seçeneklerine dayalı olarak dahil edilmeli veya eklenmemelidirse, bunu yapmak büyük olasılıkla istenen bir alternatif olmayacaktır.

Yapabileceğimiz başka bir şey, dosyayı şimdi regexps'e karşı işlemektir. sedNormalde uzun vadede çok daha etkili bir yol olan satır numarasına göre düzenlemeleri uygulayabilen bir komut dosyası üretebilir ve derlememize dahil edebiliriz.

Örneğin:

n=$(printf '\\\n\t')
grep -En 'camel|upper|lower' <infile |
sed "   1i${n%?}#!/usr/heirloom/bin/posix2001/sed -nf
        s/[^:]*/:&$n&!n;&!b&$n&/;s/://2;\$a${n%?}q"'
        s/ *cat/!/g;s/ *dog/!/g
        s| *\([cul][^ ]*\).*|s/.*/\1-case/p|'

... çıktıyı bir sedsenaryo şeklinde yazan ve ...

#!/usr/heirloom/bin/posix2001/sed -nf
:1
    1!n;1!b1
    1s/.*/camel-case/p
:2
    2!n;2!b2
    2!!s/.*/camel-case/p
:5
    5!n;5!b5
    5s/.*/upper-case/p
:6
    6!n;6!b6
    6s/.*/lower-case/p
q

Bu çıktı, makinemdeki yürütülebilir bir metin dosyasına kaydedilip şu şekilde ./bang.sedçalıştırıldığında ./bang.sed ./infile, çıktı şu şekildedir:

camel-case
upper-case
lower-case

Şimdi bana sorabilirsiniz ... Bunu neden yapmak isteyeyim ki? Neden sadece grepmaçları tutturmuyorum? Kim deve kasasını kullanıyor ki? Ve her soruya sadece cevaplayabiliyorum, hiçbir fikrim yok ... çünkü bilmiyorum. Bu soruyu okumadan önce ben şahsen multi-! spec ayrıştırma gereksinimi - Ben oldukça temiz bir yakalamak olduğunu düşünüyorum.

Çoklu! şey yoktu çok - gerçi hemen bana mantıklı sedşartname basitçe ayrıştırılır ve basitçe doğru içindir oluşturulan sed komut. Muhtemelen bu bağlamda daha anlamlı olmak \niçin gerekli ewline sınırlayıcılarını bulacaksınız ve [wr:bt{]bu fikri aklınızda tutarsanız, spesifikasyonun diğer bazı yönlerini daha iyi anlayabilirsiniz - ( :adresleri kabul qetmemek ve reddetmek gibi) kabul fazla 1) .

Örnekte ben belli bir formu yazma yukarıda sedsadece edebilirsiniz senaryo hiç bir kere okunabilir. Sıkı bakarsanız sed, düzenleme dosyasını okurken bir komut bloğundan diğerine ilerlediğini fark edebilirsiniz - düzenleme dosyası ile tamamen bitene kadar asla düzenleme komut dosyasından ayrılmaz veya tamamlanmaz.

Ben bunu multi-! adresler bu bağlamda diğerlerinden daha yararlı olabilir, ancak dürüst olmak gerekirse, onu çok iyi bir şekilde kullanabileceğim tek bir durum düşünemiyorum - ve sedçok fazla. Ayrıca, GNU / BSD'lerin sedher ikisinin de belirtildiği gibi ele alamamasının önemli olduğunu düşünüyorum - bu muhtemelen çok talep edilen spesifikasyonun bir yönü değildir ve bu yüzden bir uygulama göz ardı ederse hatalarının @ kutusunun sonuç olarak çok korkunç.

Dedi ki, başarısızlık belirtildiği gibi bu işlemek için olan uyum için herhangi bir uygulama için bir hata hangi miş ve ben için denir edilir burada alakalı dev kutuları bir e-posta çekim düşünüyorum bu yüzden, ben eğer yapmazsan bunu yapmak niyetinde.


1
Şimdi OpenBSD akımında düzeltildi.
lcd047

1
Çoklu !özellik bir sonraki spesifikasyonda kaldırılacak , burada neler oluyor!
cuonglm

@cuonglm - çok az geç, sanırım. belki işarete düşündüğümden daha yakındım.
mikeserv

@cuonglm - tamam, tamam, ama bu ne demek ... Marked olarak kabul edildi bile ne demek?
mikeserv

1
@mikeserv: cevap merakımı açıkladı ve bana sed API ile başka bir görüş verdi Bana mantıklı geliyor!
cuonglm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.