【问题标题】:Adding hours to all the timestamps in a text file将小时数添加到文本文件中的所有时间戳
【发布时间】:2020-05-07 05:53:02
【问题描述】:

我有以下文本文件 (file.dat):

random text 2019-10-10 20:22:33.456000^ text random 2019-11-30 23:45:56.789000 random
2019-11-11 21:22:33.456000 random stuffs,2019-10-31 23:45:56.789000
random, random 2019-10-10 20:22:33.456000^ text everywhere 2019-12-31 23:45:56.789000

我的目标是为该文本文件中的每个时间戳 ('YYYY-MM-DD HH:MM:SS') 添加 7 小时。

想要的输出如下:

random text 2019-10-11 03:22:33.456000^ text random 2019-12-01 06:45:56.789000 random
2019-11-12 04:22:33.456000 random stuffs,2019-11-01 06:45:56.789000
random, random 2019-10-11 03:22:33.456000^ text everywhere 2020-01-01 06:45:56.789000

我目前对此有一个解决方案,但对于只有 10,000 行的文本文件,最多需要 1 分钟。我目前的方式如下:

awk '{ip=$0;while(match(ip,/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]/,a)){ cmd="date +\"%F %T\" -d \"" a[0] " 7 hours \""; cmd | getline b; close(cmd); sub(a[0],b$0);ip=substr(ip,RSTART+RLENGTH)}; print $0}' file.dat

这需要太多时间,因为我的文本文件最多可以有 1,000,000 行。此外,我还没有检查,但我认为其中的sub 函数可能会导致问题。

因此,我一直在尝试寻找其他选择:

  1. 使用sed:

    sed "s#([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})#$(date -d '\1' +'%F %T')#g" file.dat
    

    当然没用,报错invalid date \\1'。这并不奇怪,因为我没想到后面的引用会在里面起作用。

  2. 使用awk

    awk '{print gensub(/([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9]) ([0-9][0-9]):([0-9][0-9]):([0-9][0-9])/,strftime("%Y-%m-%d %H:%M:%S",mktime("\\1 \\2 \\3 \\4 \\5 \\6")),"g",$0)}' file.dat
    

    我对这个有希望,但输出错误:

    random text 1970-01-01 06:59:59.456000^ text random 1970-01-01 06:59:59.789000 random
    1970-01-01 06:59:59.456000 random stuffs,1970-01-01 06:59:59.789000
    random, random 1970-01-01 06:59:59.456000^ text everywhere 1970-01-01 06:59:59.789000
    

    所有的时间戳都变成了 1970-01-01 06:59:59,这基本上意味着mktime 返回了-1

还有其他选择吗?任何有效的方式(使用 bash)都可以。

【问题讨论】:

  • 时间戳格式不是固定的吗?这意味着有些日期和时间之间有一个空格,而有些则在两者之间有一个逗号。
  • 整个文本文件中的所有时间戳都是“YYYY-MM-DD HH:MM:SS”(日期和时间之间有一个空格)。我选择省略毫秒,因为在时间戳中添加小时时它会保持不变。
  • 第二行中的2019-11-11,21:22:33.456000这个表达式呢?它包含逗号而不是空格。
  • 顺便说一句,您在awk 脚本中多次生成date 命令作为子进程,这将是一个瓶颈。使用mktime()strftime() 使用纯awk 会很有效。
  • 1.那是一个错字,我很抱歉。 2. 我以第二种方式使用了 mktime 和 strftime,但没有工作,但我还没有尝试在我当前工作的解决方案中替换日期。我会试一试。谢谢:)

标签: shell date awk sed


【解决方案1】:

请您尝试关注一下。

awk '
{
  line=$0
  while(match($0,/[0-9]+-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+/)){
     val=substr($0,RSTART,RLENGTH)
     split(val,array,"[- :.]")
     var=mktime(array[1] " " array[2] " " array[3] " " array[4] " " array[5]" " array[6])+(3600*7)
     new_val=strftime("%Y-%m-%d %H:%M:%S",var)
     $0=substr($0,RSTART+RLENGTH)
     sub(val,new_val,line)
     delete array
     val=var=new_val=""
  }
  print line
  line=""
}
'  Input_file

输出如下。

random text 2019-10-11 03:22:33.456000^ text random 2019-12-01 06:45:56.789000 random
2019-11-12 04:22:33.456000 random stuffs,2019-11-01 06:45:56.789000
random, random 2019-10-11 03:22:33.456000^ text everywhere 2020-01-01 06:45:56.789000

说明:为上述代码添加详细说明。请向右滚动以查看说明:)

awk '                                                                                                 ##Starting awk program.
{
  line=$0                                                                                             ##Creating variable line with current line.
  while(match($0,/[0-9]+-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+/)){                                       ##Running a loop till matches found in line.
     val=substr($0,RSTART,RLENGTH)                                                                    ##Creating val whose value is matched sub-string by match func.
     split(val,array,"[- :.]")                                                                        ##Splitting val into array with delimiters - space : and dot.
     var=mktime(array[1] " " array[2] " " array[3] " " array[4] " " array[5]" " array[6])+(3600*7)    ##Changing array values into epoch time adding 3600*7 seconds too
     new_val=strftime("%Y-%m-%d %H:%M:%S",var)                                                        ##Creating variable new_val changing epoch time to date format.
     $0=substr($0,RSTART+RLENGTH)                                                                     ##Resetting current line value to rest of the line, to remove previous matched values from it.
     sub(val,new_val,line)                                                                            ##Substituting val with new_val in line.
     delete array                                                                                     ##Deleting array here.
     val=var=new_val=""                                                                               ##Nullifying all variables here.
  }
  print line                                                                                          ##Printing variable line here.
  line=""                                                                                             ##Nullifying variable line here.
}
'  Input_file                                                                                           ##Mentioning Input_file name here.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-21
    • 2010-11-10
    • 1970-01-01
    • 2019-04-30
    • 2014-11-06
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多