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
Если вы хотите воспроизвести эту проблему:
- Скачать файл: uBXr0r15.txt.
- запустите скрипт Awk.
- Поиск "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
, или вам нужен первоначальный заказ / дублирование?
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 будет быстрее, чем вызов внешних команд.