【问题标题】:change the date formats to modified ISO date in multiple column in each line using awk or sed使用 awk 或 sed 在每行的多列中将日期格式更改为修改后的 ISO 日期
【发布时间】:2020-09-16 12:45:46
【问题描述】:

输入文件

xyz|name1|address1|19600221|M|country1|20200129|etc1
xyz|name2|address2|19610321|M|country2|20200118|etc1
xyz|name3|address3|19520217|M|country3||etc1
xyz|name4|address4|19611111|M|country4||etc1

预期输出

xyz|name1|address1|1960-02-21|M|country1|2020-01-29|etc1
xyz|name2|address2|1961-03-21|M|country2|2020-01-18|etc1
xyz|name3|address3|1952-02-17|M|country3||etc1
xyz|name4|address4|1961-11-11|M|country4||etc1

我使用的代码

awk -F"|" '{OFS="|";$4=strftime("%Y-%m-%d", $4); print$0}' input.txt

并将输出重定向到新文件并为第 7 列运行相同的内容,但结果与预期不符,我得到了以下结果

 xyz|name1|address1|1960-02-21|M|country1|1970-08-22|etc1
    xyz|name2|address2|1961-03-21|M|country2|1970-08-22|etc1
    xyz|name3|address3|1952-02-17|M|country3|1970-01-01|etc1
    xyz|name4|address4|1961-11-11|M|country4|1970-01-01|etc1

我不明白为什么第 7 列的输出不同?关于这里有什么问题的任何建议?

【问题讨论】:

  • 1961-0-321?那是什么星球?
  • 行星错字!对不起
  • strftime 预计自纪元以来的秒数。 strftime("%Y-%m-%d",19610321) = 1970-08-16
  • 只是一般注意事项:只要您可以仅使用 string 函数修改 awk 中的日期时间格式,就这样做,不要使用 time 函数。

标签: linux date awk sed


【解决方案1】:

您可以为此使用

$ sed -E 's/([0-9]{4})([0-9]{2})([0-9]{2})/\1-\2\-\3/g' input.txt
xyz|name1|address1|1960-02-21|M|country1|2020-01-29|etc1
xyz|name2|address2|1961-03-21|M|country2|2020-01-18|etc1
xyz|name3|address3|1952-02-17|M|country3||etc1
xyz|name4|address4|1961-11-11|M|country4||etc1

【讨论】:

    【解决方案2】:

    请您尝试以下操作。使用 GNU awk 中的示例编写和测试。

    awk '
    BEGIN{
      FS=OFS="|"
    }
    {
      $7=($7!=""?substr($7,1,4)"-"substr($7,5,2)"-"substr($7,7):"")
    }
    1' Input_file
    

    说明:为上述添加详细说明。

    awk '                                         ##Starting awk program from here.
    BEGIN{                                        ##Starting BEGIN section from here.
      FS=OFS="|"                                  ##Starting field separator and output field separator as | here.
    }
    {
      $7=($7!=""?substr($7,1,4)"-"substr($7,5,2)"-"substr($7,7):"")  ##Checking condition if 7th field is NOT NULL then using sub string to make them into the date exact format.
    }
    1                                             ##1 will print current edited/non-edited line here.
    ' Input_file                                  ##Mentioning Input_file name here.
    

    注意:如果您有一个或多个具有日期的列,并且您想将它们更改为 yyyy-mm-dd 格式等,那么您可以使用 for 循环,例如for (i=1;i<=NF;i++){if($i~/^[0-9]{8}$/){substr(..code above)...}

    【讨论】:

      【解决方案3】:

      这不是答案,而是扩展评论。

      @thanasisp 的评论是正确的。 @RavinderSingh13 的答案显示了如何拆分然后将日期片段加入所需的格式。如果你想使用时间函数,你仍然需要这样做:

      # reformatdate.awk
      
      BEGIN {FS = OFS = "|"}
      
      function formatDate(d,    t) {
        t = mktime(substr(d,1,4) " " substr(d,5,2) " " substr(d,7,2) " 0 0 0")
        return strftime("%Y-%m-%d", t)
      }
      
      {
        $4 = formatDate($4)
        if ($7) $7 = formatDate($7)
        print
      }
      

      然后

      $ gawk -f reformatdate.awk input.txt
      xyz|name1|address1|1960-02-21|M|country1|2020-01-29|etc1
      xyz|name2|address2|1961-03-21|M|country2|2020-01-18|etc1
      xyz|name3|address3|1952-02-17|M|country3||etc1
      xyz|name4|address4|1961-11-11|M|country4||etc1
      

      【讨论】:

      • 展示得非常好。我已经看到这是 awk 的一个警告:为了产生(真实的)时间,你必须给 mktime() 一个特定的格式。没有(类似python的)strptime(),只有strftime()。
      • 顺便说一句,这不仅是一个扩展评论,也是一个答案。
      • @thanasisp GNU awk 有一个 strptime(),但它在 gawk 扩展库中,gawkextlib 以及 JSON、CSV 和 XML 解析器扩展等。请参阅我的 cmets unix.stackexchange.com/questions/608568/… 和 @ 987654322@了解更多信息。
      • @EdMorton 我想这不是标准功能的原因(性能、兼容性?)但我没有尝试过。
      • @thanasisp 提供者的主要论点似乎是 a) 并非每个具有 gawk 的平台都有 gawk 可以调用的底层 strptime() 原语,b) 他们只是想添加所有新功能到 gawkextlib..
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多