Fórum Ubuntu CZ/SK

Ubuntu pro osobní počítače => Software => Příkazový řádek a programování pro GNU/Linux => Téma založeno: Uran 15 Března 2012, 08:30:30

Název: sed a specificky blok textu
Přispěvatel: Uran 15 Března 2012, 08:30:30
Potreboval bych ze souboru vypsat jen urcite bloky textu. Jsou ohranicene unikatnim retezcem "###". Uvnitr bloku je slovo co hledam

Takze:

Kód: [Vybrat]
###
pin
pong
pan
###
dgd

dvdfg
dfg
dsd
sd
sdv
dg
dg
dsg
dgdgfgs


###
vfdfdf
dfsdfsf
ccc
###

dokazi vypsat vsechny bloky ohranicene ###

Kód: [Vybrat]
cat sed-test | sed -n '/###/,/###/p'jen nevim jak tam dostat podminku aby vypsalo jen ty, ktere obsahuji napr. pin.

Zkousel jsem:

Kód: [Vybrat]
cat sed-test | sed -n '/###/,/pin/,/###/p'
sed: -e výraz č. 1, znak 12: neznámý příkaz: „,“

ale to je asi pekna blbost.

Rad bych to resil pomoci bashe/sed/awk/grep. Perl a podobne moc nechapu.

Název: Re:sed a specificky blok textu
Přispěvatel: daysleeper 15 Března 2012, 11:45:02
Podle mě není možné v address range zadat více adres než dvě, takže budeš muset použít další sed příkaz nebo grep.
Kód: [Vybrat]
cat sed-test | sed -n '/###/,/###/p' | grep pong
Název: Re:sed a specificky blok textu
Přispěvatel: Uran 15 Března 2012, 12:18:39
Podle mě není možné v address range zadat více adres než dvě, takže budeš muset použít další sed příkaz nebo grep.
Kód: [Vybrat]
cat sed-test | sed -n '/###/,/###/p' | grep pong

No me jde o to abych vypreparoval konkretni blok. Takze pokud to spravne chapu tak vyse uvedeny prikaz 1. vypreparuje bloky ohranicene ### 2. z techto bloku vypreparuje radky s pong coz ovsem nepotrebuji. Chci cele bloky s hledanym slovem. Jinak jeste je problem v tom, ze bloky nemaji pevny pocet radek, ale meni se - 3 a vice radku.
Název: Re:sed a specificky blok textu
Přispěvatel: ntz_reloaded 15 Března 2012, 12:29:13
Kód: [Vybrat]
> printf "%s\n" a b a w a b a | sed '/^b/,/^b/s/a/x/'
a
b
x
w
x
b
a

^^ tohodle chces docilit ? asi to nechapu
Název: Re:sed a specificky blok textu
Přispěvatel: GdH 15 Března 2012, 13:38:11
Kód: [Vybrat]
awk '/^###/{o=p;p="";getline};r&&!p{print substr(o,0,(length(o)-1));exit};{p=p$0"\n"};/pong/{r=1}'
Název: Re:sed a specificky blok textu
Přispěvatel: Uran 15 Března 2012, 18:24:40
Kód: [Vybrat]
awk '/^###/{o=p;p="";getline};r&&!p{print substr(o,0,(length(o)-1));exit};{p=p$0"\n"};/pong/{r=1}'

Ok. Musim to nejak promyslet a po vikendu se ozvu. V bashi awk ... jsem zacatecnik a tu konstrukci awk moc nechapu. Asi se budu muset o bahi/awk/.... neco doucit. Takze bych tuto diskuzi na chvilku zmrazil a az to pochopim/vyresim tak dam vedet.
Název: Re:sed a specificky blok textu
Přispěvatel: daysleeper 15 Března 2012, 21:21:06
No me jde o to abych vypreparoval konkretni blok. Takze pokud to spravne chapu tak vyse uvedeny prikaz 1. vypreparuje bloky ohranicene ### 2. z techto bloku vypreparuje radky s pong coz ovsem nepotrebuji. Chci cele bloky s hledanym slovem. Jinak jeste je problem v tom, ze bloky nemaji pevny pocet radek, ale meni se - 3 a vice radku.
Aha, pak by mělo fungovat
Kód: [Vybrat]
sed '/###/,/###/{H;$!d;};x;/pong/!d'
Manuál třeba viz
http://www.grymoire.com/Unix/Sed.html
Název: Re:sed a specificky blok textu
Přispěvatel: GdH 15 Března 2012, 21:48:08
Kód: [Vybrat]
awk '/^###/{o=p;p="";getline};r&&!p{print substr(o,0,length(o)-1);exit};{p=p$0"\n"};/hledaný_výraz/{r=1}'
Důležité je, že v awk jsou proměnné netypové a dají se testovat a používat bez deklarace, prostě se při prvním použití samy vytvoří jako prázdné/nulové. Při použití ve stringu se bude taková proměnná chovat jako prázný řetězec, při výpočtech jako nula. Dokonce pokud bude v proměnné řetězec a vrazíte ji do matematického výrazu, bude se chovat jako nula.

Uvedený program dělá následující:
Do proměnné p si postupně načítá jednotlivé řádky souboru, které interpret awk drží vždy v proměnné $0, a odděluje je znakem nového řádku. {p=p$0"\n"}
Když narazí na řádek začínající ### odloží si obsah p (což je celý předešlý blok) do proměnné o, p smaže a načte nový řádek.
/^###/{o=p;p="";getline}
Pokud v daném bloku našel hledaný výraz, což indikuje neprázdná proměnná r ( /hledaný_výraz/{r=1} ) , a zároveň došel na konec bloku, což indikuje prázdná p, vytiskne celý blok odložený v proměnné o bez posledního znaku nového řádku a ukončí program.
r&&!p{print substr(o,0,(length(o)-1));exit}

Poskládané je to tak, aby se vyplivnul jen čistý blok, bez oddělovacích řádků.
Název: Re:sed a specificky blok textu
Přispěvatel: Uran 16 Března 2012, 11:28:00
Dekuji. Je to vyreseno.

Nekde doma mam knihu http://www.abclinuxu.cz/clanky/recenze/awk-amp-sed-prirucka-pro-davkove-zpracovani-textu takze jdu studovat.
Název: Re:sed a specificky blok textu
Přispěvatel: GdH 17 Března 2012, 15:30:01
Soudruzi, vy mě nakonec svými dotazy a špatnými řešeními ještě naučíte programovat sed a awk :D
Protože sed je přeci jen efektivnější než awk, opět jsem se začetl do manuálu a zaexperimentoval. Výsledkem je kratší a rychlejší řešení, ale netvrdím, že už to nejde optimalizovat:

Kód: [Vybrat]
sed -n '/###/{x;/hledaný_výraz/{s/^[^\n]*\n//;p;q};d};H'
Stejně jako mé awk řešení, vypíše pouze první blok, ve kterém se vyskytuje hledaný řetězec.

Ještě jedna poznámka. Obě má řešení fungují tak, že se vypíše výsledek při dosažení řádku obsahující delimiter, v tomto případě ###, tudíž vyžadují tento delimiter na konci každého bloku, který má být brán vážně. Naopak na začátku ho nepotřebují, blok se načítá vždy, pouze se při dosažení delimiteru nuluje, případně vytiskne.

Edit: I když je fakt, že vzhledem k prvnímu autorově příspěvku, kde píše, že umí vypsat všechny ohraničené bloky, jsem asi zadání nesplnil přesně.. Pak bych to opravil na:

Kód: [Vybrat]
sed -n '/###/,/###/{/###/{x;/hledaný_výraz/{s/^[^\n]*\n//;p;q};d};H}'
Název: Re:sed a specificky blok textu
Přispěvatel: daysleeper 17 Března 2012, 19:13:26
Kód: [Vybrat]
sed -n '/###/,/###/{/###/{x;//{s/###\n//;p;q};d};H}'
No není sed krásný?  ;D
Název: Re:sed a specificky blok textu
Přispěvatel: Uran 19 Března 2012, 12:46:32
Kód: [Vybrat]
sed -n '/###/,/###/{/###/{x;//{s/###\n//;p;q};d};H}'
No není sed krásný?  ;D

Je nadherny :-).
Ted prave strojove zpracovavam doc dokumenty, ktere nejsou konzistentni z hlediska formatovani tak s tim trochu zapasim, ale ono se to povede. Musi :)

Trochu jsem musel skript upravit aby se vypisovaly vsechny bloky a ne jen jeden. Ted to funguje k me spokojenosti.

Kód: [Vybrat]
#!/bin/bash
echo "Zadej entitu"
read hledam
sed -n "/#####/,/#####/{/#####/{x;/"$hledam"/{s/^[^\n]*\n/#####\n/;p};d};H}" file