Nl -s

Ok, jedno pitanje za bashere:
Imam jednu datoteku u kojoj je neki tekst. Cilj mi je da svakom redu dam broj komandom nl.
U tu svrhu sam napisao:

Međutim belaj se desi. Veličina joj je sada 0, tj. svi redovi su prazni.
Pokušaj:

daje isti rezulat.
Zašto ?

probaj:
nl -s ': ’ datoteka > tmp
cat tmp > datoteka

Sinoc kad sam ugasio racunar pao mi je odgovor na um. Bash prvo analizira komandu i ako vidi znak " > " napravi novu datoteku pod odredjenim imenom i time prepise vec postojecu. Nakon toga uzima tu datoteku(praznu), filtrira je i umjesto na stdout , salje rezultat ponovo u nju.Moze i sa tmp ali najbolje i najbrze je koristiti vi-mov interaktivni modus pa cu to i uraditi.

Probaj:

cat datoteka | nl -s ": " > datoteka

ili

nl -s ": " datoteka >> datoteka

ili

cat datoteka | cat > datoteka
cat datoteka | cat >> datoteka

gornja mi je i jasna, presjece sve sto nepase u bashov buffer.
Ali doljna, donekle i radi ispravno. Ali posle neke odredjene velicine,
na mom sistemu 16K, jednostavno poludi.

Nakon nekog vremena prekinem je sa CTRL-C i sta je nastalo?
ls -lh datoteka
-rw-r–r-- 1 xxxx xxxx 410M Dec 3 16:13 datoteka

:slight_smile:

Aha, pipe je dobro rješenje.

U ovom slucaju nije. Naime, koristenje pipe podrazumijeva pravljenje vise procesa, pri cemu svi ti procesi normalno imaju jednak prioritet izvrsenja. Osim toga, redoslijed kojim shell pravi sve te potprocese razlikuje se od shell-a do shell-a. U slucaju

$ cat datoteka | cat >datoteka

postoje dva potprocesa, i dva poziva sistemske rutine open (jednom za citanje i jednom za pisanje). Posto oba procesa imaju isti prioritet izvrsenja, ovo nije nista drugo nego race-condition. Ukoliko prvi proces prvi otvori datoteku za citanje, procitace u svoj bafer koliko moze (moja verzija cat-a ima bafer od 8 kB). Nakon toga, drugi proces (shell) otvori datoteku sa flagom O_TRUNC i unisti njen sadrzaj. Sve sto je ostalo jeste sadrzaj bafera prvog procesa, sto se kroz pipu predaje na stdin drugog procesa i (u ovom slucaju) na kraju zapisuje u datoteku. Dakle, 8 kB u mom slucaju ili 16 kB u keskovom. Ako, pak, drugi proces prvi uspije pozvati open(2), rezultat ce biti prazan fajl. Probaj ovo:

$ nice cat datoteka | cat >datoteka

Nakon dovoljnog broja pokusaja trebao bi dobiti fajl velicine 0. Ako ti to ne uspije, dodaj jos nice-ova ispred cat-a!

Sto se tice rjesenja za tvoj problem, mozes koristiti perl sa opcijom -i, koja vrsi promjene in-place bez koristenja temp fajla. Takodje, neke verzije sed-a imaju ovu opciju (konkretno GNU sed). Ovako bi to izgledalo sa perl-om:

$ perl -i -p -e 'BEGIN { $l = 0 } ++$l and s/^/$l: /' datoteka

U ovom slucaju ne moras koristiti nl, ali moras znati bar neke osnove perl-a, sto komplicira cijeli problem i ide u sasvim drugom pravcu. Ako radis sa shell-om, uobicajeno je da koristis temp fajlove, ali ako bas inisistiras, Bourne-like shell-ovi mogu i bez temp fajlova:

$ exec 3<datoteka && rm -f datoteka && nl -s ': ' <&3 >datoteka

Zao mi je sto nemam vise vremena da ti napisem kako ovo radi, ali mogu bar reci da je princip potpuno isti kao kod perl-ove -i opcije. Mislim da sam negdje na ovom forumu vec napisao nesto o tome (kljucna rijec unlink). Koristenje komande rm je nuzno, jer se rm upravo zasniva na sistemskoj rutini unlink. Probaj uraditi isto bez rm ([color=red]naravno, na nekom testnom fajlu[/color] :)!

Ok, na tu ideju:dodavanje “nice” nekom procesu , stvarno nisam dosao, ali zasto je tu nego da se koristi ? Pricali smo vec o mogucnosti sa perlom. Ako se nevaram rekao si da je pravljenje nove datoteke klasicni postupak na “unixima” za pisanje u nj’. Meni to iskreno i nesmeta. Samo sam bio zbunjen kad mi se izbrisao tekst iz datoteke koju sam obradjivao.

PS.(poslije smeca)
Kako si uspio saznati cat-ov buffer ?

… ako iz nekog razlog bas zelis izbjeci pravljenje nove datoteke (novog imena), onda mozes koristiti navedenu metodu sa exec.

$ strace -f /bin/bash -c '/bin/cat datoteka | /bin/cat >datoteka'

Evo jedno od rjesenja bez nl-a, i to preko vim-a :slight_smile:

cat fajl1 | vim -c “%s/^/=line(’.’). ’ '” -c “w! fajl2” -c “q” -

gdje je fajl1 ono sto se cita (ma nemoj :)), a fajl2 ono u sto se upisuje.
Pa neka neko kaze da vim ne valja ;).

PS.
Na kraj linije ide ‘-’ kako bi vim mogao da cita iz pipe-a. Iskusajte i izostavite taj karakter; izlaz je interesantan :).

P.
Sanel

što petljaš vi kad ti treba sed. :wink:

(pazi bogati, svašta nešto se može naučiti na ovom forumu, hoćemo još, hoćemo još)

Više na kod.linux.org.ba :slight_smile:
Isprobao sam sa vim-om i funkcioniše.

Svakako, ali ovo je kratki prikaz da se vim moze koristit kao dio neke eksterne skripte. Na ovaj nacin se mogu stampati, formatirati, html-ovati i jos kojesta, ascii fajlovi (pa i binarni). Ono, vim the swiss knife :).

Postoji i wiki uradjen u vim skriptnom jeziku (doduse radi lokalno bez web servera, ali za to je bio i zamisljen) http://www.vim.org/scripts/script.php?script_id=861

S.