GNU/Linux >> Znalost Linux >  >> Linux

Koncept 'Hold space' a 'Pattern space' v sed

@Ed Morton:Tady s tebou nesouhlasím. Našel jsem sed velmi užitečné a jednoduché (jakmile vymyslíte koncept vzoru a podržíte vyrovnávací paměti), přijdete na elegantní způsob, jak provádět víceřádkové grepování.

Vezměme si například textový soubor, který má názvy hostitelů a nějaké informace o každém hostiteli, mezi nimiž je spousta nevyžádaných věcí, o které se nezajímá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

Pro mě je to awk skript, který jen získá řádky s názvem hostitele a odpovídajícím info line by zabralo o něco více, než co jsem schopen udělat se sed:

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

výstup vypadá takto:

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

(Všimněte si, že Host: foo1 se ve výstupu objeví dvakrát.)

Vysvětlení:

  1. -n zakáže výstup, pokud není výslovně vytištěn
  2. první shoda najde a vloží Host: řádek do vyrovnávací paměti (h)
  3. druhá shoda najde další řádek Info:, ale první vymění (x) aktuální řádek ve vyrovnávací paměti vzorů za vyrovnávací paměť a vytiskne (p) Host: řádek, poté znovu vymění (x) a vytiskne (p) řádek Info:.

Ano, toto je zjednodušený příklad, ale mám podezření, že se jedná o běžný problém, který rychle vyřešil jednoduchý sed one-liner. Pro mnohem složitější úkoly, jako jsou úkoly, u kterých se nemůžete spolehnout na danou předvídatelnou sekvenci, může být awk vhodnější.


Když sed čte soubor řádek po řádku, řádek, který byl aktuálně přečten, je vložen do vzoru buffer (vzorový prostor). Vyrovnávací paměť vzorů je jako dočasná vyrovnávací paměť, zápisník, kde jsou uloženy aktuální informace. Když sed řeknete, aby tiskl, vytiskne vyrovnávací paměť vzorů.

Hold buffer / hold space je jako dlouhodobé úložiště, takže můžete něco zachytit, uložit a znovu použít později, když sed zpracovává další řádek. Zádržný prostor nezpracováváte přímo, místo toho jej musíte zkopírovat nebo připojit k prostoru vzoru, pokud s ním chcete něco udělat. Například příkaz k tisku p vytiskne pouze prostor vzoru. Podobně s pracuje s prostorem vzorů.

Zde je příklad:

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

(volba -n potlačí automatický tisk řádků)

Jsou zde tři příkazy:1!G , h a $p . 1!G má adresu 1 (první řádek), ale ! znamená, že příkaz bude proveden všude ale na prvním řádku. $p na druhou stranu se provede pouze na posledním řádku. Takže se stane toto:

  1. první řádek se přečte a automaticky vloží do prostoru vzorů
  2. na prvním řádku není proveden první příkaz; h zkopíruje první řádek do pozastavení prostor.
  3. druhý řádek nyní nahradí vše, co bylo v prostoru vzorů
  4. na druhém řádku nejprve spustíme G , připojí obsah zadržovací vyrovnávací paměti k vyrovnávací paměti vzorů a oddělí jej novým řádkem. Prostor vzoru nyní obsahuje druhý řádek, nový řádek a první řádek.
  5. Potom h příkaz vloží zřetězený obsah vyrovnávací paměti vzorů do prostoru pro uložení, který nyní obsahuje obrácené řádky dva a jedna.
  6. Přejdeme na řádek číslo tři -- přejděte k bodu (3) výše.

Nakonec, po přečtení posledního řádku a přidání prostoru pro uložení (obsahujícího všechny předchozí řádky v obráceném pořadí) do prostoru vzoru, se prostor vzoru vytiskne s p . Jak jste uhodli, výše uvedené dělá přesně to, co tac příkaz do -- vytiskne soubor obráceně.


Přestože odpověď @leden a příklad jsou pěkné, vysvětlení mi nestačilo. Musel jsem hodně hledat a učit se, než se mi podařilo pochopit, jak přesně sed -n '1!G;h;$p' funguje. Rád bych tedy rozvedl příkaz pro někoho, jako jsem já.

Nejprve se podívejme, co příkaz dělá.

$ 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

Obrátí vstup jako tac příkaz ano.

sed čte řádek po řádku, tak se podívejme, co se stane v patten prostoru a mezera pro pozastavení na každém řádku. Jako h příkaz zkopíruje obsah vzorového prostoru do zadržovacího prostoru, oba prostory mají stejný text.

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

Na posledním řádku $p vytiskne d\nc\nb\na$ který je naformátován na

d
c
b
a

Pokud chcete vidět prostor se vzorem pro každý řádek, můžete přidat l příkaz.

$ 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

Zjistil jsem, že je velmi užitečné sledovat tento video tutoriál Pochopení toho, jak sed funguje, protože chlapík ukazuje, jak bude každý prostor krok za krokem využit. Rozložení je uvedeno ve 4. tutoriálu, ale pokud neznáte sed, doporučuji zhlédnout všechna videa .

Také dokument GNU sed a výukový program Bruce Barnetta Sed jsou velmi dobré reference.


Linux
  1. Jak používat příkaz sed pro Linux

  2. Příkaz Linux Sed:Použití a příklady

  3. Manipulace s textem na příkazovém řádku pomocí sed

  1. Najít číslo řádku, které obsahuje vzor, ​​pomocí vlastního oddělovače regulárního výrazu?

  2. Přidání slova na konec řádku se Sedem?

  3. Trap, Err, A Echoing the Error Line?

  1. Manipulace s úchopy kláves a ukazatelů X na příkazovém řádku?

  2. Odstranit řádek obsahující určitý řetězec a následující řádek?

  3. Nahradit všechny nové řádky mezerníkem kromě posledního?