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}
.