gawk / awk:getline的管道日期*有时*不起作用

时间:2010-03-06 03:46:58

标签: bash awk pipe gawk getline

我正在尝试将日期从一种格式转换为另一种格式: 从例如“2005年10月29日”至2005年10月29日。 我有625个日期列表。我用Awk。

转换有效 - 大部分时间。 Hovewer,有时转换根本不会发生, 应该保持(转换)日期的变量仍然存在 未定义。

这总是发生在完全相同的行上。 在日期上显式地(从Bash shell)运行“date” 这些奇怪的行工作正常(日期被正确转换)。 - 这些行的文本内容不重要。

为什么会出现这种情况,以及如何修复脚本?
她是:

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 skript。
  3. 在bug-out-3.txt中搜索“undefined”。
    (“undefined”在我的电脑上发现了122次。)
  4. 然后你可以再次运行脚本,   和(在我的电脑上)bug-out-3.txt仍然存在   未更改 - 完全相同的日期未定义。

    (Gawk 3.1.6版,Ubuntu 9.10。)

    亲切的问候,马格努斯

3 个答案:

答案 0 :(得分:9)

每当您在awk中打开管道或文件进行读取或写入时,后者将首先检查(使用内部哈希)是否已有管道或文件同名(仍然)打开;如果是这样,它将重用现有的文件描述符,而不是重新打开管道或文件。

在您的情况下,所有以undefined结尾的条目实际上都是重复的;第一次遇到它们(即首次发出相应的命令date "..." -d "..."时),将正确的结果读入x。在同一日期的后续事件中,getline尝试从原始date管道读取第二行,第三行等,即使管道已被date关闭,也会导致x {1}}不再被分配。

来自gawk手册页:

  

注意:如果使用管道,协同处理或套接字来获取getline,或者   来自循环中的print或printf,   你必须使用close()来创建新的   命令或套接字的实例。 AWK不会自动进行   关闭管道,插座或协同过程   当他们返回EOF时。

每次阅读close后,您应该明确x管道:

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

顺便说一下,sortuniq uBXr0r15.txt在输入awk之前是否可以,或者您是否需要原始排序/复制?

答案 1 :(得分:3)

虽然我喜欢awk,但这并不是必需的。

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

答案 2 :(得分:3)

 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中执行所有操作将比调用外部命令更快。