Minulla on tietotiedosto, jossa on useita tietolohkoja tiettyjen avainsanojen välissä (DATA , END). Käytän awk -sarjaa purkamaan tietolohkot erillisiksi tiedostoiksi mainitusta lohkosta otetun tiedostonimen perusteella. Koska joillakin datalohkoilla on sama nimi, nimen jokaisen ulostulotiedoston uudelleen kasvavalla kokonaisluvulla, jos tiedosto (”blockname”) on jo olemassa:
#cat input.file useless stuff1 DATA blockname1 data1 data1 END useless stuff2 DATA blockname2 data2 data2 END useless stuff3 DATA blockname1 data3 data3 END useless stuff4
Odotettavissa on kolme tulostetiedostoa blockname1, blockname2 ja blockname1_1 (huomaa, kuinka viimeiseen tiedostoon on liitetty kokonaisluku)
#cat blockname1 DATA blockname1 data1 data1 END
(muut vastaavat …)
Nyt seuraava komentosarja toimii haluamallani tavalla:
awk "BEGIN { FS=" +" } ; \ /DATA/,/END/ \ { if ( $1 ~ /DATA/ ) \ { block=$2 ; i=0 ; file=block ;\ while ( system("test ! -e " file ) ) \ { i++ ; file=block"_"i ; print file } \ } ; \ print $0 > file \ } " \ input.file
Minun ongelmani on while -silmukassa ja sen järjestelmäkutsu:
Odotin system("test -e " file) olevan TOSI, kun file on olemassa, ja FALSE, jos file ei ole vielä olemassa, ts. while -silmukka alkaa toimia vain, jos file on läsnä ja rikkoa, jos (uutta) file ei ole vielä olemassa.
Jos kuitenkin käytän system("test -e " file) (ja tee siitä sanallinen sanalla print file), minulla on loputon samanniminen silmukka, jolla on kasvava kokonaislukuliite ja päinvastainen system("test !-e " file) antaa halutun tuloksen.
Joten tämä käyttäytyy täsmälleen päinvastoin kuin odotin.
Vastaa
OK, ajattelin: ongelma on eri määritelmissä siitä, mikä on TOSI ja EPÄTOSI test: n poistumistilan ja while silmukan ehto kohdassa awk.
Postitiivinen test -komento johtaa poistumiskoodiin 0 TOSI ja negatiivinen kohdassa 1 FALSE.
Kuitenkin awk while -silmukka tulkitsee 0 -arvoksi EPÄTOSI ja 1 TOSI-arvon, täsmälleen päinvastoin määritelmä.
Esimerkkinä:
awk "{ while ( 0 ) ; { print "0" } }" file
ei pro duce minkä tahansa tuotoksen, kun taas
awk "{ while (1) ; { print "1" } }" file
tulostaa loputtomia 1 s.
Paras käytäntö on siis oltava selkeä tällaisessa yhdistelmässä.
while ( system("command") == 0 )
tai
while ( system("command") == 1 )
.
Joten minun tapauksessani
while ( system("test -e " file ) == 0 )
näyttää odotetun käyttäytymisen.
Vastaa
awk system() palauttaa suorittamasi komennon poistumistilan – 0 onnistumiselle ja! = 0 ellei menestys. Yksinkertaisen esimerkin voit kokeilla suorittamista:
v = system("date");
v on 0
jos suoritat:
v = system("dat");
v voi olla 127 tai arvo poikkeaa 0: sta, virhe palautetaan käyttöjärjestelmästä, jos dat-komento puuttuu tai sitä ei löydy.
Vastaa
Jos ymmärrän sinut, tavoitteena on purkaa input.file-tiedoston sisältö useisiin tiedostoihin välttäen saman nimisiä lohkoja.
Jos tämä on tapaus, ja jos kohdehakemisto on aina tyhjä ennen purkamista, on olemassa parempi (ja nopeampi) ratkaisu:
awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file
Tällä tavalla awk ei ”Sinun ei tarvitse suorittaa uutta kuorta N kertaa vain testataksesi, onko tiedosto olemassa.
Huomautuksia:
- BEGIN-lohkoa ei tarvita, koska awk: n kentänerotin on jo välilyöntejä.
- Rivien loppuun ei tarvita
"\"-merkkiä, koska yksittäinen lainaus on jo monirivinen.
while. Ratkaisusi on kuitenkin melko siisti – kiitos, mieluummin tämä yli iso asiani. BEGIN-lohko on jäännös eri tiedostomuodostani – unohdin, että siitä tulee hyödytön yleisessä esimerkissä. Takasuuntaisen viivan jättäminen säästää minulta ongelmia. Kiitos myös tästä. Mutta olet paikalla skriptin ' tarkoituksen suhteen. Voisitko selittään = blocks[block]++; file=block (n? "_" n: "")osan tarkemmin?blocks, joka on indeksoitu lohkon nimen mukaan. Esim. Ensimmäisessä muodossa"blockname1":blocks["blockname1"]. Awk löytää kyseisen indeksin ja koska sitä ei löydy ' t oletetaan, oletetaan""(katsotaan myös nollaksi). Nyt in awkn = var++vastaa{n=var;var++}, jotenn==""jablocks["blockname1"]==1.Lopuksifile=block (n? "_" n: "")on sama kuin{file=block;if(n!="") file+="_" n}.