gawk / awk:将日期管道传输到 getline *有时*不起作用

发布于 2024-08-23 15:23:23 字数 801 浏览 6 评论 0原文

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

大多数情况下,这种转换是有效的。 然而,有时转换根本不会发生, 并且应该保存(转换后的)日期的变量仍然存在 不明确的。

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

为什么会出现这种行为?如何修复我的脚本?
她是:

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. 在 bug-out-3.txt 中搜索“未定义”。
    (在我的电脑上,“undefined”出现了 122 次。)

然后你可以再次运行该脚本, 并且(在我的计算机上)bug-out-3.txt 仍然存在 不变——完全相同的日期未定义。

(Gawk 版本 3.1.6,Ubuntu 9.10。)

亲切的问候, Magnus

I'm attempting to convert dates from one format to another:
From e.g. "October 29, 2005" to 2005-10-29.
I have a list of 625 dates. I use Awk.

The conversion works -- most of the time.
Hovewer, sometimes the conversion won't happen at all,
and the variable supposed to hold the (converted) date remains
undefined.

This always happens with the exact same rows.
Running `date' explicitly (from the Bash shell) on the dates
of those weird rows works fine (the dates are properly converted).
-- It's not the textual contents of those rows that matters.

Why this behavior, and how can I fix my script?
Her it is:

awk 'BEGIN { FS = "unused" } { 
  x = "undefined";
  "date \"+%Y-%m-%d\" -d " $1 | getline x ;
  print $1 " = " x
}' uBXr0r15.txt \
 > bug-out-3.txt

If you want to reproduce this problem:

  1. Download this file: uBXr0r15.txt.
  2. Run the Awk skript.
  3. Search for "undefined" in bug-out-3.txt.
    ("undefined" found 122 times, on my computer.)

Then you could run the script again,
and (on my computer) bug-out-3.txt remains
unchanged -- exactly the same dates are left undefined.

(Gawk version 3.1.6, Ubuntu 9.10.)

Kind regards, Magnus

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

獨角戲 2024-08-30 15:23:23

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

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

来自 gawk 手册页:

注意:如果使用管道、协进程或套接字来获取线路,或者
来自循环内的 print 或 printf,
您必须使用 close() 来创建新的
命令或套接字的实例。 AWK 不会自动
关闭管道、套接字或协进程
当他们返回 EOF 时。

每次读完 x 后,您都应该显式地关闭管道:

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

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

Whenever you open a pipe or file for reading or writing in awk, the latter will first check (using an internal hash) whether it already has a pipe or file with the same name (still) open; if so, it will reuse the existing file descriptor instead of reopening the pipe or file.

In your case, all entries which end up as undefined are actually duplicates; the first time that they are encountered (i.e. when the corresponding command date "..." -d "..." is first issued) the proper result is read into x. On subsequent occurrences of the same date, getline attempts to read a second, third etc. lines from the original date pipe, even though the pipe has been closed by date, resulting in x no longer being assigned.

From the gawk man-page:

NOTE: If using a pipe, co-process, or socket to getline, or
from print or printf within a loop,
you must use close() to create new
instances of the command or socket. AWK does not automatically
close pipes, sockets, or co-processes
when they return EOF.

You should explicitly close the pipe every time after you have read x:

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

Incidentally, would it be OK to sort and uniq uBXr0r15.txt before piping into awk, or do you need the original ordering/duplication?

七度光 2024-08-30 15:23:23

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

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

Though I love awk it is not necessary for this.

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

子栖 2024-08-30 15:23:23
 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 中执行所有操作都会比调用外部命令更快。

 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

doing everything inside gawk will be faster than calling external commands.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文