awk systemopkald med inverteret effekt

Jeg har en datafil med flere datablokke lukket mellem specifikke nøgleord (DATA , END). Jeg bruger awk til at udtrække datablokkene i separate filer, baseret på et filnavn taget fra blokken. Da nogle datablokke har samme navn, omdøber jeg hver outputfil med et stigende heltal, hvis filen (“blockname“) allerede findes:

#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 

Forventes at være tre outputfiler blockname1, blockname2 og blockname1_1 (bemærk, hvordan den sidste fil har et heltal tildelt den)

#cat blockname1 DATA blockname1 data1 data1 END 

(de andre i overensstemmelse hermed …)

Nu fungerer følgende script som jeg vil have det:

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 

Mit problem ligger i while loop og dets systemopkald:

Jeg forventede, at system("test -e " file) ville være SAND, når file eksisterer og være FALSK, hvis file eksisterer endnu ikke, dvs. while loop kun for at starte, hvis file er til stede og at bryde, hvis (den nye) file ikke findes endnu.

Men hvis jeg bruger system("test -e " file) (og gør det ordentligt med print file), jeg har en uendelig løkke med samme navn med stigende heltalssuffiks og det modsatte system("test !-e " file) giver det ønskede resultat.

Så dette opfører sig nøjagtigt omvendt til, hvad jeg forventede.

Svar

OK, jeg regnede med: problemet ligger i de forskellige definitioner af, hvad der er SAND og FALSK mellem udgangsstatus for test og while loop-tilstand i awk.

En postiv test -kommando resulterer i en udgangskode på 0 for SAND og en negativ i 1 for FALSE.

Imidlertid i awk while loop fortolker 0 som FALSE og 1 som SAND, så nøjagtigt det modsatte definition.

Som et eksempel:

awk "{ while ( 0 ) ; { print "0" } }" file 

vil ikke være duce enhver output, mens

awk "{ while (1) ; { print "1" } }" file 

vil udskrive uendelig 1 s.

Bedste praksis skal således være eksplicit i en sådan kombination

while ( system("command") == 0 ) 

eller

while ( system("command") == 1 ) 

.

Så i mit tilfælde

while ( system("test -e " file ) == 0 ) 

viser den forventede adfærd.

Svar

awk system() returnerer en udgangsstatus for kommandoen, du kører – 0 for succes og! = 0 hvis ikke succes. For et simpelt eksempel kan du prøve at køre:

v = system("date"); 

v vil være 0

hvis du løber:

v = system("dat"); 

v kan være 127 eller en anden værdi end 0, fejlen returneres fra OS, hvis dat-kommandoen mangler eller ikke findes.

Svar

Hvis jeg forstår dig, er målet at udtrække indholdet af input.file i forskellige filer og undgå at miste blokke med samme navn.

Hvis det er tilfældet, og hvis målkataloget altid er tom før udtrækningen, er der en bedre (og hurtigere) løsning:

awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file 

På denne måde gør awk ikke “behøver at udføre en ny skal N gange bare for at teste, om der findes en fil.

Bemærkninger:

  • BEGIN-blokken er ikke nødvendigt, fordi awks feltseparator er allerede mellemrum.
  • Der er ikke behov for "\" i slutningen af linjerne, fordi det enkelte citat allerede er multiline.

Kommentarer

  • Nå, mit problem var mere til at forstå " ulige " adfærd for while -tilstanden. Men din løsning er temmelig pæn – tak, jeg foretrækker det over min klodsede ting. BEGIN-blokken er en rest fra mit forskellige filformat – jeg glemte, at det bliver ubrugeligt i mit generiske eksempel. At undlade tilbageslag vil spare mig for nogle problemer. Tak også for dette. Men du er lige ved med hensyn til scriptets ' intention. Kunne du forklare n = blocks[block]++; file=block (n? "_" n: "") -delen mere detaljeret?
  • Algoritmen bruger et array: blocks, der er indekseret efter bloknavn. Eks. I første omgang af "blockname1": blocks["blockname1"]. Awk finder det indeks, og fordi det ikke er ' t fundet antager "" (også betragtet som nul). I awk svarer n = var++ til {n=var;var++}, så n=="" og blocks["blockname1"]==1.Endelig er file=block (n? "_" n: "") det samme som {file=block;if(n!="") file+="_" n}.
  • Jeg var ikke ' t engang klar over, at en streng er en gyldig indekseringsvariabel, og er denne reducerede if-sætning – meget nyttigt, tak igen. Jeg ' er trist, jeg kan ikke give dig det " accepterede svar " her: på trods af mig vil benytte denne tilgang, da den udfører min oprindelige opgave, svarer den ikke ' t ovennævnte spørgsmål (fortolkning af tilstand i mens løkke) – det ville stride mod min forståelse af disse steder Q & Et system. Alligevel lærte jeg meget – igen tak.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *