gawk / awk: дата отправки в getline * иногда * не будет работать - PullRequest
6 голосов
/ 06 марта 2010

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

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

Это всегда происходит с одинаковыми строками. Запуск `date 'явно (из оболочки Bash) для дат из этих странных строк работает нормально (даты правильно конвертируются). - Не текстовое содержание этих строк имеет значение.

Почему такое поведение и как я могу исправить свой сценарий?
Ее это:

awk 'BEGIN { FS = "unused" } { 
  x = "undefined";
  "date \"+%Y-%m-%d\" -d " $1 | getline x ;
  print $1 " = " 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 ]

9 голосов
/ 06 марта 2010

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

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

Из справочной страницы gawk:

ПРИМЕЧАНИЕ. Если для getline используется труба, сопроцесс или сокет, или из print или printf внутри цикла, Вы должны использовать close () для создания нового экземпляры команды или сокета. AWK не автоматически закрыть трубы, розетки или сопутствующие процессы когда они возвращают EOF.

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

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

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

3 голосов
/ 06 марта 2010
 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

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

3 голосов
/ 06 марта 2010

Хотя я люблю awk, но для этого это не нужно.

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

...