【问题标题】:Use sed or awk to fix date format使用 sed 或 awk 修复日期格式
【发布时间】:2013-08-29 11:16:39
【问题描述】:

我正在尝试使用 bash 脚本将包含表格的 HTML 转换为 .csv 文件。

到目前为止,我已经完成了以下步骤:

  1. 转换为 Unix 格式(使用dos2unix
  2. 删除所有空格和制表符(使用sed 's/[ \t]//g'
  3. 删除所有空行(使用sed ':a;N;$!ba;s/\n//g')(这是必要的,因为 HTML 文件中表格的每个单元格都有一个空行...这不是我的错)
  4. 删除不必要的<td><tr> 标签(带有sed 's/<t.>//g'
  5. </td> 替换为“,”(使用sed 's/<\/td/,/g'
  6. </tr> 替换为行尾 (\n) 字符(使用 sed 's/<\/tr/\n/g'

当然,我将所有这些都放在一个管道中。到目前为止,它工作得很好。我坚持最后一步:表格有一个日期列,格式为dd/mm/yyyy,我想将它们转换为yyyy-mm-dd

有没有(简单的)方法(使用sedawk)?

数据样本(在整个sed 管道之后):

500,2,13/09/2007,30000.00,12,B-1
501,2,15/09/2007,14000.00,8,B-2

预期结果

500,2,2007-09-13,30000.00,12,B-1
501,2,2007-09-15,14000.00,8,B-2

我需要这样做的原因是因为我需要将这些数据导入 MySQL。我可以在 Excel 中打开文件并手动更改格式,但我想跳过它。

【问题讨论】:

    标签: regex bash sed awk


    【解决方案1】:
    sed "s:,\([0-9]\+\)/\([0-9]\+\)/\([0-9]\+\),:,\3-\2-\1,:"
    

    【讨论】:

      【解决方案2】:

      Awk 可以轻松完成这项任务:

      awk '
          BEGIN { FS = OFS = "," } 
          { split($3, date, /\//)
            $3 = date[3] "-" date[2] "-" date[1]
            print $0 
          }
      ' infile
      

      它产生:

      500,2,2007-09-13,30000.00,12,B-1
      501,2,2007-09-15,14000.00,8,B-2
      

      【讨论】:

        【解决方案3】:

        awk 可以解决这个问题:

        echo 08/26/2013 | awk -F/ '{printf "%s-%s-%s\n",$3,$2,$1}'
        

        这些bash-only 选项之一也是如此:

        IFS=/ read m d y < <(echo 08/26/2013); echo "${y}-${m}-${d}"
        IFS=/ read m d y <<< "08/26/2013"; echo "${y}-${m}-${d}"
        

        如果您碰巧使用ksh,其中子shell 不用于管道的最后一个组件,这应该也可以:

        echo 08/26/2013 | IFS=/ read m d y; echo "${y}-${m}-${d}"
        

        在最近的bash 中,您还可以在脚本中使用shopt -s lastpipe 以使上述调用也能正常工作,但它不能在命令行上工作(感谢下面cmets 中的@mklement0)。

        我会留给你弄清楚如何将它与其余部分集成......

        【讨论】:

        • 很好,但是基于read 的命令不起作用,因为在这种情况下readsubshel​​l 中运行;使用echo '08/26/2013' | { IFS=/ read m d y; echo "${y}-${m}-${d}"; }IFS=/ read m d y &lt;&lt;&lt;'08/26/2013'; echo "${y}-${m}-${d}"
        • @mklement0 啊,是的....忘记了那个小细节。不过,它可以在ksh 中工作。另一种选择是IFS=/ read m d y &lt; &lt;(echo 08/26/2013) 以避免子shell(尽管echo 将在子shell 中)。
        • 好点,尽管&lt;&lt;&lt; 在这里可能是最有效的。在 Bash v4.2+ 中,您还可以使用 shopt -s lastpipe(但仅限于脚本中)。我可以建议您使用其中一种可行的解决方案来更新您的答案吗?
        【解决方案4】:
        sed -E 's,([0-9]{2})/([0-9]{2})/([0-9]{4}),\3-\2-\1,g'
        

        【讨论】:

        • 将其粘贴为第一次通过示例以使事情顺利进行,并且逐字进行!谢谢@ash!
        【解决方案5】:

        对 awk 的更正假设您寻求 yyyy-mm-dd(不是 yyyy-dd-mm)

        回声 08/26/2013 | awk -F/ '{printf "%s-%s-%s\n",$3,$1,$2}'

        【讨论】:

          【解决方案6】:

          到目前为止,所有答案都非常针对 OP 的问题。这是一种更通用的方法,运行(GNU,用于-d 选项)dateawk

          awk 'BEGIN{FS=","}
               {
                 "date -d\"" $3 "\" +%Y-%m-%d" | getline mydate; 
                 print $1 "," $2 "," mydate "," $4 "," $5 "," $6
               }'
          

          当然,只有当输入日期格式由date 处理时,这种方法才能正常工作。 AFAICS 不幸的是,dd/mm/yyyy 并非如此。可以尝试other commands 而不是date(未测试)。

          编辑:实施 mklement0 的评论。

          Edit2:实际上这不适用于 mawk,这是 Debian 默认的 awk 实现。明显的解决方案是尽可能安装gawk

          【讨论】:

          • ++,但你应该提到 GNU date 是必需的,因为 -d;同样,|&amp; 是 GNU Awk 扩展,但这里实际上不需要:| 可以,这使它适用于所有 Awk。最后,我建议您在被连接的字符串之间使用空格,既是为了视觉清晰,又是为了表明 Awk 中的字符串连接与在 shell 中的工作方式不同;例如,"date -d'" $3 "' +%Y-%m-%d"(我还添加了单引号以防止字段嵌入空格)。
          • @mklement0 :感谢您的建议,我已经编辑了答案。单引号不行,我用转义的双引号代替了它们。
          • 感谢您更新答案,感谢您发现我的单引号错误(只是明确说明:单引号不能在 Awk 脚本中使用,因为整个脚本是单引号)。
          • 当有很多输入行时,这会产生不正确的结果;有关使用 close() 的正确方法,请参阅 this answer
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-19
          • 2015-03-19
          • 2017-02-12
          相关资源
          最近更新 更多