W jaki sposób polecenie sed '1! G; h; $! D' odwraca zawartość pliku?


20

Moje pytanie dotyczy sedrozwiązania specyficznego dla tej kwestii odwrotnego grepowania podanego w tej odpowiedzi . Rozwiązanie / , którego nie jestem w stanie odszyfrować, jest następujące:sedgrep

sed '1!G;h;$!d' file

Czy ktoś może odczytać to polecenie?

Wiem z wiedzy VI (M), że G oznacza ostatnią linię pliku i że w sed huk (!), Po którym następuje taka praca adresu grep -v, to znaczy, że nie będzie pasować do tej linii. Ale jako całość powyższy skrypt sed jest poza mną.


3
... bardzo powoli ...
mikeserv

1
Jak sugeruje Mikeserv. Należy zauważyć, że ten podstępny sedprzepis jest niezwykle nieefektywnym sposobem (złożoność O (n ^ 2/2)) odwracania linii w pliku. Byłoby to zbyt wolne dla plików z dużą liczbą linii. Aby uzyskać znacznie bardziej wydajną alternatywę dla odwracania kolejności wierszy, zobacz tacGNU coreutils.
arielf

Odpowiedzi:


35

Spowoduje to odwrócenie pliku linia po linii.

plik sed '1! G; h; $! d'

Po pierwsze, sedma przestrzeń wstrzymania i przestrzeń wzorów . Musimy je rozróżnić, zanim skoncentrujemy się na tym konkretnym poleceniu.

Kiedy sedczyta nowy wiersz, jest on ładowany do przestrzeni wzorów. Dlatego miejsce to jest nadpisywane za każdym razem, gdy przetwarzany jest nowy wiersz. Z drugiej strony przestrzeń wstrzymania jest spójna podczas całego przetwarzania, a wartości mogą być tam przechowywane do późniejszego wykorzystania.


Do polecenia:

Istnieją 3 komendy w tym stwierdzeniem: 1!G, hi$!d

  • 1!Goznacza, że Gpolecenie jest wykonywane w każdym wierszu oprócz pierwszego ( !neguje 1). Goznacza dołączenie tego, co znajduje się w przestrzeni wstrzymania do przestrzeni wzorów.

  • hdotyczy każdej linii. IT kopie przestrzeni wzór do miejsca przechowywania (i nadpisuje niego).

  • $!dstosuje się do każdej linii oprócz ostatniej ( $reprezentuje ostatnią linię, !neguje ją). dto polecenie usuwania linii (przestrzeni wzorów).


  1. Teraz, gdy czytany jest pierwszy wiersz, sedwykonuje hpolecenie. Pierwszy wiersz jest kopiowany do miejsca wstrzymania. Następnie jest usuwany, ponieważ spełnia $!warunek. sedkontynuuje od drugiej linii.
  2. Druga linia odpowiada warunkowi 1!(nie jest to pierwsza linia), więc przestrzeń wstrzymania (która ma pierwszą linię) jest dołączana do przestrzeni wzorów (która ma drugą linię). Następnie w przestrzeni wzorów znajduje się teraz druga linia, po której następuje pierwsza linia, ograniczona nową linią. Teraz obowiązuje hpolecenie (jak w każdym wierszu); wszystko, co znajduje się w obszarze wzorca, jest kopiowane do obszaru wstrzymania. Obowiązuje trzecia instrukcja ( $!d): wiersz jest usuwany z obszaru wzorców.
  3. Krok 2 jest teraz wykonywany ze wszystkimi liniami. Przeskakujemy do ostatniej linii.
  4. W ostatnim wierszu ( $) wykonano prawie cały krok 2, ale nie usunięto części usuwania ( d). sed, gdy zostanie wywołane bez -n, automatycznie drukuje przestrzeń wzorów na końcu przetwarzania dla każdej linii wejściowej. Tak więc, gdy nie zostanie usunięty, drukowana jest przestrzeń wzoru. Zawiera teraz wszystkie wiersze w odwrotnej kolejności .

1
@Geek Nie, hpolecenie kopiuje przestrzeń wzorów do przestrzeni wstrzymania, która trwa do sedkońca. Po zakończeniu skryptu wszystko jest czyszczone, ponieważ plik binarny został zamknięty.
chaos

2
Czy możemy myśleć o przestrzeni wstrzymania jak o rejestrach dla vima? Czy są również ponumerowane? Czy jest tylko jeden z nich?
Geek

2
@Geek W sedjest tylko jedno miejsce do przechowywania. To jest jak zmienna, która może zawierać coś.
chaos

1
@ user1717828 Gdybyśmy nie chcieli, pierwszy wiersz zostałby wydrukowany po przetworzeniu. Ponieważ sed nie jest wywoływany z, -nmusimy usunąć każdą linię oprócz ostatniej. W ostatnim wierszu sed dołącza wszystko, od przestrzeni wstrzymania do przestrzeni wzorów. A ponieważ dpolecenie nie zostanie wykonane, wiersz jest drukowany (ten wiersz zawiera teraz cały plik odwrócony).
chaos

1
(1) Podpytanie / obserwacja PO (w komentarzu) brzmi: „tak więc hpolecenie w ostatnim wierszu jest w pewnym sensie„ brakiem op ”. (Z dodatkowym naciskiem i nieco sparafrazowane). On ma rację; gdy sedprzetwarza ostatnią linię wejścia The Gczyta przestrzeń HOLD (aby dołączyć go do przestrzeni wzorzec), a następnie hkopiuje przestrzeni wzór do miejsca przechowywania, które nigdy nie zostanie ponownie odwołanie . Równie dobrze moglibyśmy powiedzieć sed 'G;$!h;$!d'lub sed 'G;$!{h;d}'. (2) Możemy uniknąć używania d, mówiąc sed -n 'G;h;$p'.
Scott
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.