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
-
Potreboval bych ze souboru vypsat jen urcite bloky textu. Jsou ohranicene unikatnim retezcem "###". Uvnitr bloku je slovo co hledam
Takze:
###
pin
pong
pan
###
dgd
dvdfg
dfg
dsd
sd
sdv
dg
dg
dsg
dgdgfgs
###
vfdfdf
dfsdfsf
ccc
###
dokazi vypsat vsechny bloky ohranicene ###
cat sed-test | sed -n '/###/,/###/p'
jen nevim jak tam dostat podminku aby vypsalo jen ty, ktere obsahuji napr. pin.
Zkousel jsem:
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.
-
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.
cat sed-test | sed -n '/###/,/###/p' | grep pong
-
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.
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.
-
> 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
-
awk '/^###/{o=p;p="";getline};r&&!p{print substr(o,0,(length(o)-1));exit};{p=p$0"\n"};/pong/{r=1}'
-
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.
-
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 fungovatsed '/###/,/###/{H;$!d;};x;/pong/!d'
Manuál třeba viz
http://www.grymoire.com/Unix/Sed.html
-
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ů.
-
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.
-
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:
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:
sed -n '/###/,/###/{/###/{x;/hledaný_výraz/{s/^[^\n]*\n//;p;q};d};H}'
-
sed -n '/###/,/###/{/###/{x;//{s/###\n//;p;q};d};H}'
No není sed krásný? ;D
-
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.
#!/bin/bash
echo "Zadej entitu"
read hledam
sed -n "/#####/,/#####/{/#####/{x;/"$hledam"/{s/^[^\n]*\n/#####\n/;p};d};H}" file