2010-03-06 3 views
5

Estoy intentando convertir fechas de un formato a otro: De p. Ej. "29 de octubre de 2005" a 2005-10-29. Tengo una lista de 625 fechas. Yo uso Awk.gawk/awk: fecha de la tubería para getline * algunas veces * no funcionará

La conversión funciona, la mayoría de las veces. Hovewer, a veces la conversión no ocurrirá en absoluto, y la variable que se supone que contiene la fecha (convertida) permanece indefinida.

Esto siempre ocurre exactamente con las mismas filas. Ejecutar `fecha 'explícitamente (desde el shell Bash) en las fechas de esas filas extrañas funciona bien (las fechas se convierten correctamente). - No son los contenidos textuales de esas filas lo que importa.

¿Por qué este comportamiento y cómo puedo corregir mi script? Su
es:

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

Si desea reproducir este problema:

  1. Descargar este archivo: uBXr0r15.txt.
  2. Ejecute el Awr skript.
  3. Buscar "indefinido" en bug-out-3.txt.
    ("indefinido" que se encuentra 122 veces, en mi equipo.)

entonces se podría ejecutar el script de nuevo, y (en mi equipo) insecto-hacia fuera-3.txt permanece sin cambios - exactamente el las mismas fechas quedan sin definir.

(versión 3.1.6 Gawk, Ubuntu 9.10.)

Saludos cordiales, Magnus

Respuesta

8

Siempre que abre un tubo o un archivo para leer o escribir en awk, este último comprobará primero (usando un hash interna) si ya dispone de una tubería o archivo con el mismo nombre (Sigue abierto; si es así, reutilizará el descriptor de archivo existente en lugar de volver a abrir la tubería o el archivo.

En su caso, todas las entradas que terminan como undefined son en realidad duplicados; la primera vez que se encuentran (es decir, cuando se emite por primera vez el comando correspondiente date "..." -d "...") se lee el resultado correcto en x. En sucesos posteriores de la misma fecha, getline intenta leer una segunda, una tercera línea etc. de la tubería original date, aunque la tubería se haya cerrado por date, lo que ocasiona que x ya no se asigne.

Desde el gawk hombre-página:

NOTA: Si se utiliza un tubo, co-proceso, o la toma de getline, o de impresión o printf dentro de un bucle, se debe utilizar cerca (a) para crear nuevas instancias del comando o socket. AWK no cierra automáticamente las tuberías, los zócalos o los coprocesos cuando devuelven EOF.

Usted debe explícitamente close el tubo cada vez que después de haber leído x:

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

Por cierto, ¿Estaría bien a sort y uniquBXr0r15.txt antes del conexionado en awk, o necesita la orden original /¿duplicación?

+0

Esto resuelve mi problema, gracias. No necesito el pedido original y si reordenar mis indata, el problema también desapareció, y supongo que ahorraré algo de CPU. (Los datos indata del mundo real también contienen filas sin fecha, por lo que no puedo usar 'sort 'y' uniq', y el script Awk real es algo diferente.) – KajMagnus

+0

Gracias, esto también resuelve mi problema: recibía un error "Demasiados archivos abiertos" y se preguntó cómo cerrar estos "archivos" porque no sabía que awk usa archivos para esas operaciones de tubería. – flo

+0

Me di cuenta de este problema en la posterior llamada de una función para resembrar al azar. –

3

Aunque Me encanta AWK no es necesario para esto.

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

+0

Gracias, no sabía que podía hacer eso. El ejemplo en mi publicación original es un ejemplo simplificado. Mi script Awk real es algo más largo, y el archivo de entrada real también contiene filas sin fecha. – 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 

haciendo todo dentro de gawk será más rápido que llamar a comandos externos.

+0

Esta fue una solución ambiciosa :-) Funciona bien. Está bien para mí esperar esas fracciones de segundo más largas que las otras soluciones :-) – KajMagnus

Cuestiones relacionadas