Gawk / awk: дата трубопроводов * иногда * не будет работать
Вопрос
Я пытаюсь преобразовать даты одного формата в другое: от EG «29 октября 2005 года» до 2005-10-29. У меня есть список из 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
Если вы хотите воспроизвести эту проблему:
- Загрузите этот файл: UBXR0R15.txt..
- Запустите скритп awk.
- Поиск "undefined" в Bug-Out-3.txt.
(«undefined» нашел 122 раза на моем компьютере.)
Тогда вы можете снова запустить скрипт, а (на моем компьютере) Bug-Out-3.txt остается без изменений - точно такие же даты остаются неопределенными.
(GAWK версия 3.1.6, Ubuntu 9.10.)
Добрые пожелания, магнус
Решение
Всякий раз, когда вы открываете трубу или файл для чтения или записи в awk
, последний сначала проверка (Использование внутреннего хеша) У него уже есть труба или файл с тем же именем (Все еще открыт; если так, Он повторно использует существующий файловый дескриптор вместо того, чтобы открывать трубу или файл.
В вашем случае все записи, которые в конечном итоге undefined
на самом деле дубликаты; Первый раз, когда они встречаются (то есть когда соответствующая команда date "..." -d "..."
сначала выпущен) правильный результат читается в x
. Отказ На последующих случаях одинаковой даты, getline
пытается прочитать вторую, третью и т. Д. Линии из оригинала date
труба, даже если труба была закрыта date
, в результате чего x
больше не назначен.
Из gawk
Man-Page:
Примечание. При использовании трубы, совместного процесса или розетки для GetLine или от печати или распечатки внутри цикла вы должны использовать Close () для создания новых экземпляров команды или сокета. Awk не автоматически закрывает трубы, розетки или со-процессы, когда они возвращают eof.
Вы должны явно close
Труба каждый раз после того, как вы прочитали x
:
close("date \"+%Y-%m-%d\" -d " $1)
Кстати, это будет хорошо 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(/["]/,"",$1)
gsub(/["]/,"",$4)
t=mktime($4" "months[$1]" "$2" 0 0 0")
print strftime("%Y-%m-%d",t)
}' uBXr0r15.txt
Делать все внутри Gawk будет быстрее, чем вызывая внешние команды.