chiamata di sistema awk con effetto invertito

Ho un file di dati con più blocchi di dati racchiusi tra parole chiave specifiche (DATA , END). Sto usando awk per estrarre i blocchi di dati in file separati, in base a un nome di file preso da detto blocco. Poiché alcuni blocchi di dati condividono lo stesso nome, rinomino ogni file di output con un numero intero crescente se il file (“blockname“) esiste già:

#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 

Sono previsti tre file di output blockname1, blockname2 e blockname1_1 (nota come lultimo file ha un numero intero assegnato)

#cat blockname1 DATA blockname1 data1 data1 END 

(gli altri di conseguenza …)

Ora il seguente script funziona come voglio:

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 

Il mio problema risiede con il ciclo while e la sua chiamata di sistema:

Mi aspettavo che system("test -e " file) fosse TRUE quando file esiste e che fosse FALSE se file non esiste ancora, ovvero il while ciclo da avviare solo se file è presente e rompere se (il nuovo) file non esiste ancora.

Tuttavia, se uso system("test -e " file) (e rendilo dettagliato con print file), ho un ciclo infinito con lo stesso nome con suffisso intero crescente e system("test !-e " file) fornisce il risultato desiderato.

Quindi si comporta esattamente in modo inverso a quello che mi aspettavo.

Risposta

OK, ho pensato: il problema risiede nelle diverse definizioni di cosa è VERO e FALSO tra lo stato di uscita di test e while condizione del ciclo in awk.

Un comando test postive restituisce un codice di uscita 0 per TRUE e uno negativo in 1 per FALSE.

Tuttavia, in awk il while loop interpreta 0 come FALSE e 1 come TRUE, quindi esattamente lopposto definizione.

Ad esempio:

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

non pro duce qualsiasi output, mentre

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

stamperà infiniti 1 s.

Best practice deve quindi essere esplicito in tale combinazione

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

o

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

rispettivamente.

Quindi nel mio caso

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

mostra il comportamento previsto.

Risposta

awk system() restituisce uno stato di uscita del comando che esegui: 0 per successo e! = 0 se non ha successo. Per un semplice esempio puoi provare a eseguire:

v = system("date"); 

v sarà 0

se esegui:

v = system("dat"); 

v potrebbe essere 127 o un valore diverso da 0, lerrore restituito dal sistema operativo se il comando dat è mancante o non trovato.

Risposta

Se ti capisco, lobiettivo è estrarre il contenuto di input.file in vari file evitando di perdere blocchi con lo stesso nome.

Se questo è il caso e, se la directory di destinazione è sempre vuota prima dellestrazione, allora cè una soluzione migliore (e più veloce):

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

In questo modo awk non “Non è necessario eseguire una nuova shell N volte solo per verificare se il file esiste.

Note:

  • Non è necessario il blocco BEGIN, perché il separatore di campo di awk sono già spazi.
  • Non è necessario "\" alla fine delle righe, perché le virgolette singole sono già su più righe.

Commenti

  • Bene, il mio problema era più nella comprensione del comportamento " dispari " della condizione while. Comunque la tua soluzione è abbastanza chiara – grazie, preferisco questa rispetto alla mia cosa ingombrante. Il blocco BEGIN è un residuo del mio diverso formato di file: ho dimenticato che diventa inutile nel mio esempio generico. Tralasciare il backslash mi risparmierà qualche problema. Grazie anche per questo. Ma sei a posto per quanto riguarda lintenzione dello script '. Potresti spiegare la parte n = blocks[block]++; file=block (n? "_" n: "") in modo più dettagliato?
  • Lalgoritmo utilizza un array: blocks che è indicizzato per nome del blocco. Ex. Nella prima istanza di "blockname1": blocks["blockname1"]. Awk, trova quellindice e poiché non è ' t trovato assume "" (considerato anche zero). Ora, in awk n = var++ è equivalente a {n=var;var++}, quindi n=="" e blocks["blockname1"]==1.Infine file=block (n? "_" n: "") è uguale a {file=block;if(n!="") file+="_" n}.
  • Non ero ' Anche consapevole che una stringa è una variabile di indicizzazione valida e di questa istruzione if ridotta – molto utile, grazie ancora. Sono ' rattristato di non poterti dare la " risposta accettata " qui: nonostante me adotterà questo approccio poiché adempie al mio compito iniziale, non ' risponde alla domanda precedente (interpretazione della condizione nel ciclo while) – andrebbe contro la mia comprensione di questi siti D & Un sistema. Tuttavia, ho imparato molto, grazie ancora.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *