Am un fișier de date cu mai multe blocuri de date închise între cuvinte cheie specifice (DATA
, END
). Folosesc awk
pentru a extrage blocurile de date în fișiere separate, pe baza unui nume de fișier preluat din blocul menționat. Deoarece unele blocuri de date au același nume, redenumesc fiecare fișier de ieșire cu un număr întreg în creștere dacă fișierul („blockname
„) există deja:
#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
Se așteaptă trei fișiere de ieșire blockname1
, blockname2
și blockname1_1
(rețineți cum ultimul fișier are un număr întreg atribuit)
#cat blockname1 DATA blockname1 data1 data1 END
(celelalte în consecință …)
Acum următorul script funcționează așa cum vreau eu:
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
Problema mea rezidă în bucla while
și apelul său de sistem:
Mă așteptam ca system("test -e " file)
să fie ADEVĂRAT atunci când există file
și să fie FALS dacă file
nu există încă, adică bucla while
pentru a începe să ruleze numai dacă file
este prezent și a sparge dacă (noul) file
nu există încă.
Totuși, dacă folosesc system("test -e " file)
(și faceți-o detaliată cu print file
), am o buclă infinită cu același nume cu sufix întreg în creștere și opusul system("test !-e " file)
oferă rezultatul dorit.
Deci, acest lucru se comportă exact invers față de ceea ce mă așteptam.
Răspuns
OK, m-am gândit: problema constă în diferitele definiții ale ceea ce este ADEVĂRAT și FALS între starea de ieșire a test
și while
starea buclei în awk
.
O comandă test
pozitivă are ca rezultat un cod de ieșire al 0
pentru TRUE și unul negativ în 1
pentru FALSE.
Cu toate acestea, în awk
bucla while
interpretează 0
ca FALS și 1
ca ADEVĂRAT, deci exact opusul definiție.
De exemplu:
awk "{ while ( 0 ) ; { print "0" } }" file
nu va pro produce orice ieșire, în timp ce
awk "{ while (1) ; { print "1" } }" file
va imprima infinit 1
s.
Cele mai bune practici trebuie astfel să fie explicit într-o astfel de combinație
while ( system("command") == 0 )
sau
while ( system("command") == 1 )
Deci, în cazul meu
while ( system("test -e " file ) == 0 )
arată comportamentul așteptat.
Răspuns
awk
system()
returnează starea de ieșire a comenzii pe care o executați – 0 pentru succes și! = 0 dacă nu succes. Pentru un exemplu simplu, puteți încerca să rulați:
v = system("date");
v va fi 0
dacă rulați:
v = system("dat");
v poate fi 127 sau o valoare diferită de 0, eroarea a revenit din sistemul de operare dacă comanda dat lipsește sau nu este găsită.
Răspuns
Dacă vă înțeleg, scopul este extragerea conținutului input.file în diferite fișiere, evitând pierderea blocurilor cu același nume.
Dacă acesta este și, dacă directorul țintă este întotdeauna gol înainte de extracție, atunci există o soluție mai bună (și mai rapidă):
awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file
În acest mod awk doesn „Nu trebuie să executați un shell nou de N ori doar pentru a testa dacă fișierul există.
Note:
- Nu este nevoie de blocul BEGIN, deoarece separatorul de câmp awk este deja spații.
- Nu este nevoie de
"\"
la sfârșitul liniilor, deoarece ghilimelul unic este deja multiliniu.
while
. Cu toate acestea, soluția dvs. este destul de îngrijită – vă mulțumesc, prefer, asta în locul chestiei mele voluminoase. Blocul BEGIN este un rest din formatul meu diferit de fișier – am uitat că devine inutil în exemplul meu generic. Lăsând înapoi backslash-ul îmi va scuti de unele probleme. Mulțumesc și pentru asta. Dar sunteți la fața locului cu privire la intenția scriptului '. Ați putea explica partean = blocks[block]++; file=block (n? "_" n: "")
mai detaliat?blocks
care este indexată după numele blocului. Ex. În prima instanță a"blockname1"
:blocks["blockname1"]
. Awk găsi acel index și pentru că nu este ' găsit presupune""
(considerat și zero). Acum, în awkn = var++
este echivalent cu{n=var;var++}
, decin==""
șiblocks["blockname1"]==1
.În cele din urmă,file=block (n? "_" n: "")
este același lucru cu{file=block;if(n!="") file+="_" n}
.