awk-järjestelmän kutsu, jolla on käänteinen vaikutus

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.

Kommentit

  • No, ongelmani oli enemmän ymmärrystä " outoa " -tilan käyttäytymisestä 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?
  • Algoritmi käyttää yhtä taulukkoa: 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 awk n = var++ vastaa {n=var;var++}, joten n=="" ja blocks["blockname1"]==1.Lopuksi file=block (n? "_" n: "") on sama kuin {file=block;if(n!="") file+="_" n}.
  • En ollut ' t edes tietoinen siitä, että merkkijono on kelvollinen indeksointimuuttuja ja onko tämä pienennetty if-käsky – erittäin hyödyllinen, kiitos vielä kerran. Olen ' m surullinen. En voi antaa sinulle " hyväksyttyä vastausta " täällä: minusta huolimatta omaksumalla tämän lähestymistavan, kun se täyttää alkuperäisen tehtäväni, se ei ' ei vastaa yllä olevaan kysymykseen (ehdon tulkinta silmukassa -tilan tulkinta) – se olisi ristiriidassa näkemykseni kanssa näistä sivustoista Q & Järjestelmä. Kuitenkin opin paljon – kiitos vielä kerran.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *