Я пытаюсь преобразовать даты от одного формата до другого: От, например, "29 октября 2005" до 29.10.2005. У меня есть список 625 дат. Я использую Awk.
Работы преобразования - большую часть времени. Hovewer, иногда преобразования не будет происходить вообще, и переменная, которая, как предполагают, содержала (преобразованную) дату, остается неопределенной.
Это всегда происходит с теми же самыми строками. Рабочая 'дата' явно (от оболочки Bash) в даты тех странных строк хорошо работает (даты правильно преобразовываются). - Это не текстовое содержание тех строк, который имеет значение.
Почему это поведение, и как я могу исправить свой сценарий?
Ее это:
awk 'BEGIN { FS = "unused" } {
x = "undefined";
"date \"+%Y-%m-%d\" -d " $1 | getline x ;
print $1 " = " x
}' uBXr0r15.txt \
> bug-out-3.txt
Если Вы хотите воспроизвести эту проблему:
Затем Вы могли запустить скрипт снова, и (на моем компьютере), bug-out-3.txt остается неизменным - точно, те же даты оставляют неопределенными.
(Версия 3.1.6 простофили, Ubuntu 9.10.)
С наилучшими пожеланиями, Magnus
Каждый раз, когда вы открываете канал или файл для чтения или записи в awk
, последний сначала проверяет (используя внутренний хеш) , есть ли уже канал или файл с тем же именем (все еще) открыт; если это так, он будет повторно использовать существующий дескриптор файла вместо повторного открытия канала или файла.
В вашем случае все записи, которые заканчиваются как undefined
, на самом деле дублируются; в первый раз, когда они встречаются (т.е. когда соответствующая команда date "..." -d "..."
выполняется впервые) правильный результат считывается в x
. При последующих повторениях той же даты getline
пытается прочитать вторую, третью и т. Д. Строки из исходного конвейера date
, даже если конвейер был закрыт к date
, в результате чего x
больше не назначается.
Из справочной страницы gawk
:
ПРИМЕЧАНИЕ. При использовании конвейера, совместного процесса или сокета для получения строки или из print или printf внутри цикла, { {1}} вы должны использовать close () для создания новых экземпляров команды или сокета. AWK не закрывает автоматически каналы, сокеты или совместные процессы , когда они возвращают EOF.
Вы должны явно закрывать
канал каждый раз после чтения x
:
close("date \"+%Y-%m-%d\" -d " $1)
Между прочим, можно ли сортировать
и uniq
uBXr0r15.txt
перед подключением к awk
, или вам нужен исходный порядок / дублирование?
Хотя я люблю awk, в этом нет необходимости.
tr -d '"'
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 будет быстрее, чем вызов внешних команд.