gawk / awk: дата трубопровода для getline * иногда* не будет работать

Я пытаюсь преобразовать даты из одного формата в другой: Например, с "29 октября 2005 года" по 2005-10-29 годы. У меня есть список из 625 дат. Я использую Awk.

преобразование работает -- большую часть времени. Hovewer, иногда преобразование не произойдет вообще, и переменная, которая должна содержать (преобразованную) дату, остается не определено.

это всегда происходит с одними и теми же строками. Запуск "даты" явно (из оболочки Bash) на датах из этих странных строк отлично работает (даты правильно перевести). -- Дело не в текстовом содержании этих строк.

почему такое поведение, и как я могу исправить мой скрипт?
Вот она:

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

Если вы хотите воспроизвести эту проблему:

  1. Скачать файл: uBXr0r15.txt.
  2. запустите скрипт Awk.
  3. Поиск "undefined" в bug-out-3.формат txt.
    ("undefined" найдено 122 раза, на моем компьютер.)

затем вы можете снова запустить скрипт, и (на моем компьютере) bug-out-3.txt остается без изменений - точно такие же даты остаются неопределенными.

(Gawk версии 3.1.6, Ubuntu 9.10.)

С уважением, Магнус

3 ответов


всякий раз, когда вы открываете канал или файл для чтения или записи в awk, последний сначала проверить (используя внутренний хэш) имеет ли он уже канал или файл с тем же именем (все еще) открыть; если это так, он будет повторно использовать существующий файловый дескриптор вместо повторного открытия трубы или файла.

в вашем случае все записи, которые заканчиваются как undefined фактически дубликаты; первый раз, когда они встречаются (т. е. когда соответствующая команда date "..." -d "..." сначала выдается) правильный результат считывается в x. О последующих событиях той же даты,getline пытается прочитать второй, третий и т. д. строки из оригинала date труба, хотя труба была закрыта date, в результате x больше не назначается.

С gawk man-page:

Примечание: при использовании трубы, совместного процесса или сокета для getline или из print или printf в цикле, вы должны использовать метод close() для создания нового экземпляры команды или сокета. AWK не делает автоматически закрыть трубы, розетки, или co-процессов когда они вернутся EOF.

вы должны явно close труба каждый раз после того, как вы прочитали x:

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

кстати, было бы хорошо sort и uniq uBXr0r15.txt перед кантом в awk, или вам нужен первоначальный заказ / дублирование?


хотя я люблю awk, это не обязательно для этого.

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


 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(/["]/,"",)
      gsub(/["]/,"",)
      t=mktime(" "months[]" "" 0 0 0")
      print strftime("%Y-%m-%d",t)
    }' uBXr0r15.txt

выполнение всего внутри gawk будет быстрее, чем вызов внешних команд.