Jeg har en datafil med flere datablokker som er lukket mellom bestemte nøkkelord (DATA
, END
). Jeg bruker awk
for å trekke ut datablokkene i separate filer, basert på et filnavn hentet fra blokken. Siden noen datablokker har samme navn, omdøper jeg hver utdatafil med et økende heltall hvis filen («blockname
«) allerede eksisterer:
#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
Forventet ville være tre utdatafiler blockname1
, blockname2
og blockname1_1
(merk hvordan den siste filen har et heltall tildelt den)
#cat blockname1 DATA blockname1 data1 data1 END
(de andre tilsvarende …)
Nå fungerer følgende skript som jeg vil ha 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
Problemet mitt ligger i while
loop og systemanropet:
Jeg forventet at system("test -e " file)
skulle være SANT når file
eksisterer og å være FALSE hvis file
eksisterer ennå ikke, dvs. while
sløyfen som bare begynner å kjøre hvis file
er tilstede og å bryte hvis (den nye) file
ikke eksisterer ennå.
Men hvis jeg bruker system("test -e " file)
(og gjør det ordentlig med print file
), jeg har en uendelig løkke med samme navn med økende heltalssuffiks og det motsatte system("test !-e " file)
gir ønsket resultat.
Så dette oppfører seg nøyaktig omvendt til det jeg forventet.
Svar
OK, jeg skjønte: problemet ligger i de forskjellige definisjonene av hva som er SANT og FALSK mellom utgangsstatusen til test
og while
sløyfetilstand i awk
.
En postiv test
-kommando resulterer i en utgangskode på 0
for SANT og negativ i 1
for FALSE.
Imidlertid, i awk
while
sløyfen tolker 0
som FALSE og 1
som SANT, så akkurat det motsatte definisjon.
Som et eksempel:
awk "{ while ( 0 ) ; { print "0" } }" file
vil ikke pro duce hvilken som helst utgang, mens
awk "{ while (1) ; { print "1" } }" file
vil skrive ut uendelig 1
s.
Beste praksis er således å være eksplisitt i en slik kombinasjon
while ( system("command") == 0 )
eller
while ( system("command") == 1 )
.
Så i mitt tilfelle
while ( system("test -e " file ) == 0 )
viser forventet oppførsel.
Svar
awk
system()
returnerer en utgangsstatus for kommandoen du kjører – 0 for suksess og! = 0 hvis ikke suksess. For et enkelt eksempel kan du prøve å kjøre:
v = system("date");
v blir 0
hvis du løper:
v = system("dat");
v kan være 127 eller verdien er forskjellig fra 0, feilen returneres fra operativsystemet hvis dat-kommandoen mangler eller ikke blir funnet.
Svar
Hvis jeg forstår deg, er målet å trekke ut innholdet i input.file i forskjellige filer, og unngå å miste blokker med samme navn.
Hvis det er tilfelle, og hvis målkatalogen alltid er tom før ekstraksjonen, er det en bedre (og raskere) løsning:
awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file
På denne måten gjør awk ikke «t trenger å utføre et nytt skall N ganger bare for å teste om filen eksisterer.
Merknader:
- BEGIN-blokken er ikke nødvendig, fordi awks feltskiller er allerede mellomrom.
- Det er ikke behov for
"\"
på slutten av linjene, fordi enkelt sitatet allerede er flerlinjet.
while
-tilstanden. Løsningen din er imidlertid ganske ryddig – takk, jeg foretrekker, dette fremfor min klumpete ting. BEGIN-blokken er en rest fra mitt forskjellige filformat – jeg glemte at den blir ubrukelig i mitt generelle eksempel. Å utelate tilbakeslaget vil spare meg for noen problemer. Takk for dette også. Men du er klar over angående skriptets ' intensjon. Kan du forklaren = blocks[block]++; file=block (n? "_" n: "")
-delen mer detaljert?blocks
som er indeksert etter blokknavn. Eks. I første omgang av"blockname1"
:blocks["blockname1"]
. Awk finner den indeksen, og fordi den ikke er ' t funnet antar""
(også ansett som null). Nå tilsvarern = var++
{n=var;var++}
, sån==""
ogblocks["blockname1"]==1
.Endelig erfile=block (n? "_" n: "")
det samme som{file=block;if(n!="") file+="_" n}
.