apel de sistem awk cu efect inversat

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.

Comentarii

  • Ei bine, problema mea a înțeles mai mult " odd " comportamentul 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 partea n = blocks[block]++; file=block (n? "_" n: "") mai detaliat?
  • Algoritmul folosește o matrice: 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 awk n = var++ este echivalent cu {n=var;var++}, deci n=="" și blocks["blockname1"]==1.În cele din urmă, file=block (n? "_" n: "") este același lucru cu {file=block;if(n!="") file+="_" n}.
  • Nu eram ' chiar știți că un șir este o variabilă de indexare validă și este o declarație if redusă – foarte utilă, mulțumesc din nou. ' mă întristez nu vă pot oferi " răspuns acceptat " aici: în ciuda mea urmând să adopt această abordare întrucât îmi îndeplinește sarcina inițială, nu ' nu răspunde la întrebarea de mai sus (interpretarea stării în bucla while) – ar merge împotriva înțelegerii mele despre acest site Q & Un sistem. Totuși, am învățat multe – mulțumesc din nou.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *