2010-03-06 11 views
5

Sto tentando di convertire le date da un formato all'altro: Da ad es. "29 ottobre 2005" al 2005-10-29. Ho una lista di 625 date. Io uso Awk.gawk/awk: piping date to getline * a volte * non funziona

La conversione funziona - la maggior parte del tempo. Hovewer, a volte la conversione non si verifica affatto, e la variabile che si presume abbia la data (convertita) rimane indefinita.

Ciò accade sempre con le stesse righe identiche. L'esecuzione "data" esplicitamente (dalla shell Bash) nelle date di quelle righe strane funziona correttamente (le date vengono convertite correttamente). - Non è il contenuto testuale di quelle file che conta.

Perché questo comportamento e come posso correggere il mio script?
Il suo è:

awk 'BEGIN { FS = "unused" } { 
    x = "undefined"; 
    "date \"+%Y-%m-%d\" -d " $1 | getline x ; 
    print $1 " = " x 
}' uBXr0r15.txt \ 
> bug-out-3.txt 

Se si desidera riprodurre il problema:

  1. Scarica questo file: uBXr0r15.txt.
  2. Esegui lo script Awk.
  3. Cerca "non definito" in bug-out-3.txt.
    ("indefinito" trovato 122 volte, sul mio computer.)

allora si potrebbe eseguire lo script di nuovo, e (sul mio computer) bug-out-3.txt rimane invariato - esattamente la le stesse date non sono state definite.

(Gawk versione 3.1.6, Ubuntu 9.10.)

Cordiali saluti, Magnus

risposta

8

Ogni volta che si apre un tubo o un file per la lettura o la scrittura in awk, quest'ultimo controllerà prima (usando un hash interna) se ha già un tubo o un file con lo stesso nome (ancora aperto; in tal caso, riutilizzerà il descrittore di file esistente invece di riaprire la pipa o il file.

Nel tuo caso, tutte le voci che finiscono come undefined sono in realtà duplicati; la prima volta che vengono rilevati (vale a dire quando viene emesso il comando corrispondente date "..." -d "..."), il risultato corretto viene letto in x. Nelle occorrenze successive della stessa data, getline tenta di leggere una seconda, terza, ecc. Linee dalla pipe originale date, anche se la pipe è stata chiusa da date, con conseguente x non più assegnato.

Dal gawk man-page:

NOTA: Se si usa un tubo, co-processo, o la presa a getline, o da stampa o printf all'interno di un ciclo, è necessario utilizzare close() per creare nuove istanze del comando o del socket . AWK non automaticamente chiude pipe, socket o co-processi quando restituiscono EOF.

Si dovrebbe esplicitamente close il tubo ogni volta dopo aver letto x:

close("date \"+%Y-%m-%d\" -d " $1) 

Per inciso, sarebbe OK per sort e uniquBXr0r15.txt prima di tubazioni in awk, o avete bisogno l'ordinamento originale /duplicazione?

+0

Questo risolve il mio problema, grazie. Non ho bisogno dell'originale e se riordino il mio indata il problema è sparito - e salvo qualche CPU suppongo. (Il mondo reale contiene anche righe non datate, quindi non posso usare 'sort 'e' uniq ', e lo script di Awk è in qualche modo diverso.) – KajMagnus

+0

Grazie, questo risolve anche il mio problema - stavo ricevendo un errore "Troppi file aperti" e mi chiedevo come chiudere questi "file" perché non sapevo che awk usasse i file per quelle operazioni di pipe. – flo

+0

Ho notato questo problema nella chiamata successiva di una funzione a reseeding casuali. –

3

se amo AWK non è necessario per questo.

tr -d '"' < uBXr0r15.txt | date +%Y-%m-%d -f -

+0

Grazie, non sapevo che avrei potuto farlo. L'esempio nel mio post originale è un esempio semplificato. Il mio vero script Awk è un po 'più lungo e il vero file di input contiene anche righe non datate. – KajMagnus

3
gawk 'BEGIN{ 
     m=split("January|February|March|April|May|June|July|August|September|October|November|December",d,"|") 
     for(o=1;o<=m;o++){ 
      months[d[o]]=sprintf("%02d",o) 
     } 
     FS="[, ]" 
    } 
    { 
     gsub(/["]/,"",$1) 
     gsub(/["]/,"",$4) 
     t=mktime($4" "months[$1]" "$2" 0 0 0") 
     print strftime("%Y-%m-%d",t) 
    }' uBXr0r15.txt 

fare tutto all'interno di gawk sarà più veloce di chiamare comandi esterni.

+0

Questa era una soluzione ambiziosa :-) Funziona bene. Va bene per me aspettare le frazioni di un secondo più a lungo le altre soluzioni però :-) – KajMagnus