Sed'de 'Hold space' ve 'Pattern space' Kavramı


87

Sed'deki iki kavram kafamı karıştırdı: tutma alanı ve desen alanı. Biri onları açıklamaya yardım edebilir mi?

İşte kılavuzun bir parçası:

h H    Copy/append pattern space to hold space.
g G    Copy/append hold space to pattern space.

n N    Read/append the next line of input into the pattern space.

Bu altı komut gerçekten kafamı karıştırıyor.


4
Kendiniz deneyin:echo $'1\n2\n3\n4' | sed -n '1~2h;2~2{p;x;p}'
choroba

4
Kafanız karışmasın, sadece kullanmayın. Tek bir satırdaki basit değişikliklerin dışında herhangi bir şey için sed değil awk kullanmalısınız. Tutma boşlukları, desen boşlukları ve sed dil yapılarının% 95'i daha iyi bir alternatif olmadığında awk'den önce icat edildi. Awk 1970'lerin ortalarında icat edilir edilmez demode oldular ve bugün sadece awk'de basitçe ve kurnazca yapmaktansa seds arcane sözdizimini kullanarak problem çözmekten hoşlanan insanlar tarafından hayatta tutuluyorlar. Sed'de s, g ve p'den (-n ile) daha fazlasını kullanıyorsanız, neredeyse kesin olarak yanlış aracı kullanıyorsunuz demektir.
Ed Morton

27
Morton awk, yapılandırılmış verilerle çalışır (her satır aynı yapıya sahiptir). Sed, ham rastgele verilerle çalışmak içindir. Yani sed yerine sadece awk kullanamazsınız.
Pithikos

5
Okumanızı şiddetle tavsiye ederim info sed. Çıplak adam sayfasından çok daha detaylı.
Fernando Basso

4
Pithikos'a katılıyorum. Morton'un yaptığı gibi şeritten aşağı indim ve kendime Morton'un sorduğu soruyu sordum. Ancak sed'i henüz bu kadar kolay reddedemezdim.
eigenfield

Yanıtlar:


116

Sed bir dosyayı satır satır okuduğunda, halihazırda okunan satır şablon ara belleğine (desen alanı) eklenir . Desen tamponu, geçerli bilgilerin depolandığı geçici tampon, çalışma alanı gibidir. Sed'e yazdırmasını söylediğinizde, desen tamponunu yazdırır.

Tampon / tutma alanı, bir şeyi yakalayabileceğiniz, depolayabileceğiniz ve daha sonra sed başka bir hattı işlerken yeniden kullanabileceğiniz uzun vadeli bir depolama gibidir. Muhafaza alanını doğrudan işlemezsiniz, bunun yerine, onunla bir şey yapmak istiyorsanız kopyalamanız veya desen alanına eklemeniz gerekir. Örneğin, yazdırma komutu pyalnızca desen alanını yazdırır. Aynı şekilde sdesen uzayında çalışır.

İşte bir örnek:

sed -n '1!G;h;$p'

(-n seçeneği satırların otomatik yazdırılmasını engeller)

Orada üç komutlar burada: 1!G, hve $p. 1!Gbir adresi vardır 1(ilk satır), ancak !komutun her yerde, ancak ilk satırda yürütüleceği anlamına gelir . $pÖte yandan yalnızca son satırda yürütülecektir. Öyleyse ne olur:

  1. ilk satır okunur ve otomatik olarak desen boşluğuna eklenir
  2. ilk satırda ilk komut yürütülmez; hilk satırı muhafazaya kopyalar alanına .
  3. şimdi ikinci satır, desen uzayında olanın yerini alıyor
  4. ikinci satırda, önce çalıştırıyoruz G tutma tamponunun içeriğini desen tamponuna ekleyerek, onu bir satırsonu ile ayırarak çalıştırıyoruz. Desen alanı artık ikinci satırı, bir yeni satırı ve ilk satırı içerir.
  5. Ardından hkomut, desen arabelleğinin birleştirilmiş içeriğini artık iki ve bir ters çevrilmiş satırları tutan tutma alanına ekler.
  6. Üçüncü satıra geçiyoruz - yukarıdaki (3) noktasına gidin.

Son olarak, son satır okunduktan ve bekletme alanı (önceki satırların tümünü ters sırada içeren) desen boşluğuna eklendikten sonra desen boşluğu ile yazdırılır p. Tahmin ettiğiniz gibi, yukarıdaki tackomut tam olarak ne yaptığını yapar - dosyayı tersine yazdırır.


3
G ve h seçeneği "kes ve ekle" gibi çalışıyor mu? "Kopyala ve ekle" işlemine benzemiyor.
gülümse

İç içe geçmiş komutlar (süslü parantezler) kullanıldığında desen ve tutma boşluğunun sonuna ne eklenir? '195,210{/add/p}'… Bir desende yer alan bir grup çizginin son satırını çıkarmak mümkün müdür?
Sandburg

17

@Ed Morton: Burada sana katılmıyorum. Çok sedsatırlı grepleme yapmanın zarif bir yolunu bulmak için çok kullanışlı ve basit buldum (bir kez desen kavramını alıp tamponları tuttuğunuzda).

Örneğin, ana bilgisayar adları ve her ana bilgisayar hakkında bazı bilgiler içeren, aralarında pek umursamadığım pek çok önemsiz metin dosyası alalım.

Host: foo1
some junk, doesnt matter
some junk, doesnt matter
Info: about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Info: a second line about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Host: foo2
some junk, doesnt matter
Info: about foo2 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter

Bana göre, sadece ana bilgisayar adı ve karşılık gelen infosatır ile satırları almak için bir awk betiği sed ile yapabileceğimden biraz daha fazlasını alacaktır:

sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt

çıktı şöyle görünür:

Host: foo1
Info: about foo1 that I really care about!!
Host: foo1
Info: a second line about foo1 that I really care about!!
Host: foo2
Info: about foo2 that I really care about!!

( Host: foo1Çıktıda iki kez göründüğüne dikkat edin.)

Açıklama:

  1. -n açıkça yazdırılmadıkça çıktıyı devre dışı bırakır
  2. ilk eşleşme, Host:satırı bulur ve tutma arabelleğine (h) koyar
  3. ikinci eşleşme, sonraki Bilgi: satırını bulur, ancak ilk önce şablon tamponundaki geçerli satırı (x) tutma arabelleği ile değiştirir ve Host:satırı yazdırır (p) , sonra yeniden değiştirir (x) ve Bilgi: satırını yazdırır (p).

Evet, bu basit bir örnek, ancak bunun basit bir sed tek astar tarafından hızla çözülen yaygın bir sorun olduğundan şüpheleniyorum. Belirli, tahmin edilebilir bir sıraya güvenemeyeceğiniz çok daha karmaşık görevler için awk daha uygun olabilir.


2
Bu durumda grep kullanabilirsiniz:grep 'Host\|Info'
Pithikos

Belirli bir Sunucudan sonra iki Bilgi satırı varsa, @JensJenson her iki Bilgi satırının da bir Bilgi satırından önce gelmesini ister. Sanırım yanıtı buna göre düzenleyeceğim. Pithikos, grep o zaman yeterli olmayacak.
Aaron McDaid

4
@JensJenson, awksed kodunuzun eşdeğeri de oldukça kısa:awk '/Host:/{hold=$0}; /Info/{print hold; print;}' myfile.txt
Aaron McDaid

13

@ Ocak'ın cevabı ve örneği güzel olsa da açıklama bana yetmedi. Tam olarak nasıl sed -n '1!G;h;$p'çalıştığını anlayana kadar çok şey araştırmak ve öğrenmek zorunda kaldım . Bu yüzden, benim gibi biri için emir üzerinde ayrıntıya girmek istiyorum.

Öncelikle komutun ne yaptığını görelim.

$ echo {a..d} | tr ' ' '\n' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;$p'
d
c
b
a

Girişi şu şekilde ters çevirir: tac komutun yaptığı .

sedsatır satır okur, öyleyse hadi desen alanında ve her satırdaki bekletme alanında ne olduğunu görelim . Gibi hkomut kopya tutma boşluğuna desen alanının içeriği, her iki boşluk, aynı metin var.

Read line    Pattern Space / Hold Space    Command executed
-----------------------------------------------------------
a            a$                            h
b            b\na$                         1!G;h
c            c\nb\na$                      1!G;h
d            d\nc\nb\na$                   1!G;h;$p

Son satırda, biçimlendirilmiş $pbaskılard\nc\nb\na$

d
c
b
a

Her satırın desen boşluğunu görmek isterseniz bir lkomut ekleyebilirsiniz .

$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;l;$p'
a$
b\na$
c\nb\na$
d\nc\nb\na$
d
c
b
a

Adam her bir alanın nasıl kullanılacağını adım adım gösterdiği için, sed'in nasıl çalıştığını anlamakla ilgili bu eğitim videosunu izlemenin çok faydalı olduğunu gördüm . Ayırma aralığı 4. öğreticide belirtilmiştir, ancak aşina değilseniz tüm videoları izlemenizi öneririm sed.

Ayrıca GNU sed belgesi ve Bruce Barnett'in Sed öğreticisi çok iyi referanslardır.


2
Bir şey eklemediğimiz sürece, tüm pratik amaçlar için saklama alanının boş olduğunu belirtmenin de faydalı olacağını düşünüyorum.
Naveed
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.