Koncepcje „przestrzeni ładunkowej” i „przestrzeni wzorcowej” w sed

86

Mylą mnie dwie koncepcje sed: trzymaj przestrzeń i przestrzeń wzorców. Czy ktoś może pomóc je wyjaśnić?

Oto fragment instrukcji:

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.

Te sześć poleceń naprawdę mnie zmyliło.

ChenQi
źródło
4
Spróbuj sam:echo $'1\n2\n3\n4' | sed -n '1~2h;2~2{p;x;p}'
choroba
4
Nie daj się zmylić, po prostu ich nie używaj. Do czegokolwiek innego niż zwykłe podstawienia w jednej linii, powinieneś używać awk, a nie sed. Przestrzenie wstrzymania, przestrzenie wzorców i 95% konstrukcji języka sed zostały wynalezione przed awk, kiedy nie było lepszej alternatywy. Stały się przestarzałe, gdy tylko awk został wynaleziony w połowie lat siedemdziesiątych i są utrzymywane przy życiu tylko dzisiaj przez ludzi, którzy lubią rozwiązywać problemy przy użyciu arkanowej składni seds, zamiast robić to w awk w prosty i zwięzły sposób. Jeśli używasz więcej niż s, gip (z -n) w sed, prawie na pewno używasz niewłaściwego narzędzia.
Ed Morton,
26
Morton awk pracuje z danymi strukturalnymi (każda linia ma taką samą strukturę). Sed jest przeznaczony do pracy z surowymi danymi losowymi. Nie możesz więc po prostu użyć awk zamiast sed.
Pithikos,
5
Gorąco polecam lekturę info sed. Jest znacznie bardziej szczegółowy niż sama strona podręcznika.
Fernando Basso
4
Zgadzam się z Pithikosem. Poszedłem na dół, tak jak Morton, i zadałem sobie to samo pytanie co Morton. Jednak nie mogłem jeszcze tak łatwo odrzucić seda.
eigenfield

Odpowiedzi:

111

Kiedy sed czyta pliku linia po linii, linia, która została obecnie odczytać jest włożona do wzorca bufora (wzór przestrzeni). Bufor wzorców jest jak tymczasowy bufor, notatnik, w którym przechowywane są bieżące informacje. Kiedy każesz sedowi wydrukować, wypisuje bufor wzorca.

Hold buffer / hold space jest jak przechowywanie długoterminowe, tak że możesz coś złapać, zapisać i ponownie użyć później, gdy sed przetwarza kolejną linię. Nie przetwarzasz bezpośrednio przestrzeni do przechowywania, zamiast tego musisz ją skopiować lub dołączyć do przestrzeni wzoru, jeśli chcesz coś z nią zrobić. Na przykład polecenie print pdrukuje tylko obszar wzoru. Podobnie sdziała na przestrzeni wzorców.

Oto przykład:

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

(opcja -n wyłącza automatyczne drukowanie linii)

Istnieją trzy komendy tutaj: 1!G, hi $p. 1!Gma adres 1(pierwsza linia), ale !oznacza, że ​​polecenie zostanie wykonane wszędzie z wyjątkiem pierwszej linii. $pz drugiej strony zostanie wykonany tylko w ostatniej linii. A więc co się dzieje:

  1. pierwsza linia jest odczytywana i wstawiana automatycznie do przestrzeni wzoru
  2. w pierwszej linii pierwsze polecenie nie jest wykonywane; hkopiuje pierwszą linię do przestrzeni ładunkowej .
  3. teraz druga linia zastępuje wszystko, co było w przestrzeni wzoru
  4. w drugiej linii najpierw wykonujemy G, dołączając zawartość bufora wstrzymującego do bufora wzorców, oddzielając ją znakiem nowej linii. Przestrzeń wzoru zawiera teraz drugą linię, nową linię i pierwszą linię.
  5. Następnie hpolecenie wstawia połączoną zawartość bufora wzorców do przestrzeni wstrzymania, która teraz zawiera odwrócone wiersze dwa i jeden.
  6. Przechodzimy do linii numer trzy - przejdź do punktu (3) powyżej.

Na koniec, po przeczytaniu ostatniej linii i dołączeniu do przestrzeni wzoru miejsca przechowywania (zawierającego wszystkie poprzednie wiersze w odwrotnej kolejności), wypisywany jest znak p. Jak się domyślasz, powyższe robi dokładnie to samo, co tacpolecenie - wyświetla plik w odwrotnej kolejności.

styczeń
źródło
3
Czy opcja G i h działa jak „wytnij i dołącz”? Nie wygląda to na operację „kopiuj i dołącz”.
Uśmiechnij się
Co dodaje się do wzoru i utrzymuje spację, gdy używane są zagnieżdżone polecenia (nawiasy klamrowe)? '195,210{/add/p}'… Czy można wyodrębnić ostatnią linię z grupy linii wchodzących w skład wzorca?
Sandburg
17

@Ed Morton: Nie zgadzam się z tobą tutaj. Znalazłem sedbardzo przydatne i proste (kiedy już poznasz koncepcję wzorca i trzymasz bufory), aby wymyślić elegancki sposób wykonywania greppingu wielowierszowego.

Na przykład weźmy plik tekstowy, który zawiera nazwy hostów i kilka informacji o każdym hoście, z mnóstwem śmieci pomiędzy nimi, o które nie dbam.

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

Dla mnie skrypt awk, który po prostu pobrałby wiersze z nazwą hosta i odpowiadającą im infolinią, zająłby trochę więcej niż to, co jestem w stanie zrobić z sedem:

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

wyjście wygląda następująco:

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!!

(Zauważ, że Host: foo1na wyjściu pojawia się dwukrotnie).

Wyjaśnienie:

  1. -n wyłącza wyjście, chyba że zostanie wyraźnie wydrukowane
  2. pierwsze dopasowanie, wyszukuje i umieszcza Host:linię w buforze wstrzymania (h)
  3. drugie dopasowanie, znajduje następną linię Info:, ale najpierw zamienia (x) bieżącą linię w buforze wzorca z buforem wstrzymującym i drukuje (p) Host:linię, następnie ponownie zamienia (x) i drukuje (p) linię Info:.

Tak, to jest uproszczony przykład, ale podejrzewam, że jest to powszechny problem, który został szybko rozwiązany przez prosty jednowierszowy sed. W przypadku dużo bardziej złożonych zadań, takich jak te, w których nie można polegać na danej, przewidywalnej sekwencji, awk może być lepiej dopasowany.

Jens Jensen
źródło
2
W tym przypadku jednak możesz po prostu użyć grep:grep 'Host\|Info'
Pithikos
Jeśli po danym hoście znajdują się dwie linie informacji, @JensJenson chce, aby obie linie informacyjne były poprzedzone linią informacji. Myślę, że odpowiednio zmodyfikuję odpowiedź. Pithikos, grep nie wystarczy wtedy.
Aaron McDaid
3
@JensJenson, awkodpowiednik twojego kodu seda też jest dość krótki:awk '/Host:/{hold=$0}; /Info/{print hold; print;}' myfile.txt
Aaron McDaid
11

Chociaż odpowiedź @ January i przykład są fajne, wyjaśnienie nie było dla mnie wystarczające. Musiałem wiele szukać i się uczyć, zanim udało mi się zrozumieć, jak dokładnie sed -n '1!G;h;$p'działa. Chciałbym więc rozwinąć polecenie dla kogoś takiego jak ja.

Przede wszystkim zobaczmy, co robi polecenie.

$ 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

Odwraca dane wejściowe, tak jak tacrobi to polecenie.

sedczyta wiersz po wierszu, więc zobaczmy, co się dzieje w przestrzeni wzorcowej i przestrzeni wstrzymania w każdym wierszu. Ponieważ hpolecenie kopiuje zawartość przestrzeni wzoru do przestrzeni przechowywania, obie przestrzenie mają ten sam tekst.

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

W ostatnim wierszu $pwypisuje d\nc\nb\na$formatowany do

d
c
b
a

Jeśli chcesz zobaczyć przestrzeń wzoru dla każdej linii, możesz dodać lpolecenie.

$ 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

Uważam, że bardzo pomocne jest obejrzenie tego samouczka wideo Zrozumienie, jak działa sed , ponieważ facet pokazuje krok po kroku, jak każda przestrzeń będzie używana. Odstępy między uchwytami są omówione w czwartym samouczku, ale polecam obejrzenie wszystkich filmów, jeśli nie jesteś zaznajomiony sed.

Również dokument GNU sed i tutorial Bruce'a Barnetta Sed są bardzo dobrymi odniesieniami.

Sanghyun Lee
źródło
2
Myślę, że pomocne będzie również wspomnienie, że miejsce do przechowywania wszystkich praktycznych celów jest puste, chyba że coś do niego dodamy.
Naveed