【问题标题】:Use date command within awk arguments在 awk 参数中使用 date 命令
【发布时间】:2019-03-08 21:59:30
【问题描述】:

我有一个看起来像这样的文件

server1-adm.test.com,/var,dir,29987,2007-12-03 15:52:43,root,root
server2.fs.com,/DATA_File.out,file,299076487,2008-10-15 05:12:23,user1,group1
server3-prd.mod.com,/opt,dir,29987,2009-05-03 00:13:23,user1,group1
server4,/var/tmp/xxz.zip,file,400,2007-12-03 15:52:43,root,root
server1-adm.test.com,/usr,dir,34299876,2006-12-03 16:52:43,root,root
server3-prd.mod.com,/local/home,dir,400,2009-05-03 12:13:23,user2,group1

第 5 列是我要修改的 date + time 值。我尝试将多个 awk 语句一起使用,但看起来太混乱了,容易出错。 与其使用多个语句进行日期格式转换,不如在 awk 中使用date 系统命令转换为以下结果。

server1-adm.test.com,/var,dir,29987,2007-12-03 03:52:43 PM,root,root
server2.fs.com,/DATA_File.out,file,299076487,2008-10-15 05:12:23 AM,user1,group1
server3-prd.mod.com,/opt,dir,29987,2009-05-03 00:13:23 AM,user1,group1
server4,/var/tmp/xxz.zip,file,400,2007-12-03 03:52:43 PM,root,root
server1-adm.test.com,/usr,dir,34299876,2006-12-03 04:52:43 PM,root,root
server3-prd.mod.com,/local/home,dir,400,2009-05-03 12:13:23 PM,user2,group1

date -d "2007-12-03 15:52:43" +%Y/%m/%d:%H%M%S 行中的某些内容。我不知道我们如何在date 命令中获取 AM/PM。

我已经有多个 awk 语句作为脚本的一部分一起运行,以对同一个传​​入文件执行其他文本修改,因此我想使用 awk + ​​date 语句来执行此操作。

【问题讨论】:

  • @Ed Morton,GNU awk 和 gawk 一样吗?是的,系统已经傻眼了。

标签: shell date awk


【解决方案1】:

如果您可以使用 GNU awk,它会提供一些时间函数,使您的程序运行速度比调用您的 shell + date 为您的 CSV 文件的每一行更快:

awk 'BEGIN { FS = OFS = "," } { gsub("[-:]", " ", $5); $5 = strftime("%F %r", mktime($5)) } 1'

展开形式:

awk '
    BEGIN { FS = OFS = "," }

    {
        gsub("[-:]", " ", $5)
        $5 = strftime("%F %r", mktime($5))
    }

    1
'

如果您真的想使用外部 date 命令,正如您在问题中所述,请使用 GNU awk 协同处理,以便在每一行仅启动和重用一个 date 命令:

awk 'BEGIN { FS = OFS = ","; cmd = "stdbuf -oL date -f - +%F\" \"%r" } { print $5 |& cmd; cmd |& getline $5 } 1'

展开形式:

awk '
    BEGIN {
        FS = OFS = ","
        cmd = "stdbuf -oL date -f - +%F\" \"%r"
    }

    {
        print $5 |& cmd
        cmd |& getline $5
    }

    1
'

但你真的应该采用第一个解决方案。

【讨论】:

  • 谢谢。我会坚持使用 GNU awk 时间函数。
【解决方案2】:

请您尝试关注一下。

awk -F'[ ,]' '{split($6,array,":");$6=array[1]>12?sprintf("%02d",array[1]-12)":"array[2]":"array[3]" PM":(array[1]==12?$6 " PM":$6 " AM")} 1'  Input_file

解释:这里也为上面的代码添加解释。

awk -F'[ ,]' '                                                         ##Making field separator as space and comma for all the lines of Input_file.
{
  split($6,array,":")                                                  ##using split function to split 6th field of current line by making : as field sep for it.
  $6=array[1]>12?sprintf("%02d",array[1]-12)":"array[2]":"array[3]" PM" :$6 " AM" ##re-creating $6 value by checking condition if its 1st value array value which is time is greater than 12 than subtracting its value with 12 here and adding PM and AM according to it too.
}
1                                                                      ##Mentioning 1 will print the edited/non-edited value of line.
' Input_file                                                       ##Mentioning Input_file name here.

【讨论】:

  • 我已经使用了多个 awk 语句将日期时间转换为所需的值,但我正在寻找一种在 awk 中使用 date 系统命令的更短的方法。
  • @Marcos,你试过我的一个班轮吗?这将给出正确的输出,请尝试一次,然后告诉我?
  • 是的,单线确实有效,但我正在寻找一种解决方案,我可以使用date 命令让事情变得更简单。
【解决方案3】:

您可以直接在$5 变量上使用date 命令,如下所示。小心引用命令。在这里,我们从$5 形成命令字符串cmd,并根据需要使用%p 标记,以根据一天中的时间打印适当的AMPM

awk -v FS=, -v OFS=, '{cmd = "date -d \""$5"\" \"+%Y-%m-%d %I:%M:%S %p\""}{ cmd|getline D; close(cmd); $5=D}1' file

关键部分在close(cmd) 语句中。它强制awk 每次执行cmd,因此,日期每次都是实际的。另见Using getline into a Variable from a Pipe

【讨论】:

  • 感谢您的解决方案效果很好。但是后来我不知道 GNU awk 有时间函数,因此将 xhienne 解决方案标记为答案,因为这更适合我的要求。
【解决方案4】:

Orders 是一个 csv 记录文件,每条记录包含三个字段:订单号、到期日、交货期。我想通过从截止日期中减去提前期来计算每个订单的开始日期,将结果格式化为 dd-Mmm-yyyy,并将其附加到从订单中读取的原始记录中。

awk -F, '{"date --date=\""$2" -"$3" day\" +%d-%b-%Y" | getline sd; print $1","$2","$3","sd}' orders

所以,让我们分解一下。

-F,告诉 awk 使用逗号作为字段分隔符

'{命令 | getline variable;command}' 是我希望 awk 对每条记录执行的操作

"date --date=""$2" -"$3" day" +%d-%b-%Y" 从日期 $2 中减去 $3 天 并将结果格式化为 dd-Mmm-yyyy。

命令 | getline 变量将命令的结果赋给变量

print $1","$2","$3","sd 打印所需的输出

这是结果

$ cat orders
order01,01-Mar-2024,1
order02,01-Jan-2021,2
$ awk -F, '{"date --date=\""$2" -"$3" day\" +%d-%b-%Y" | getline d; print $1","$2","$3","d}' orders
order01,01-Mar-2024,1,29-Feb-2024
order02,01-Jan-2021,2,30-Dec-2020

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-21
    • 2023-03-16
    • 2013-03-15
    • 1970-01-01
    • 2017-11-25
    • 1970-01-01
    • 2016-12-16
    • 1970-01-01
    相关资源
    最近更新 更多