【问题标题】:How to convert in file csv date in specific column to unix date如何将特定列中的文件csv日期转换为unix日期
【发布时间】:2020-11-01 15:57:42
【问题描述】:

我有一个包含这些列的文件 csv:

"Weight","Impedance","Units","User","Timestamp","PhysiqueRating"
"58.75","5.33","kg","7","2020-7-11 19:29:29","5"

当然,我可以转换日期命令: date -d '2020-7-11 19:29:29' +%s

结果: 1594488569

如何在 bash 脚本中替换 csv 文件中的这个日期?

【问题讨论】:

    标签: date awk sed cut


    【解决方案1】:

    GNU sed

    sed -E '2,$ s/(("[^"]*",){4})("[^"]+")(.*)/echo \x27\1"\x27$(date -d \3 +%s)\x27"\4\x27/e'
    
    • 2,$ 跳过标头处理
    • (("[^"]*",){4})前四列
    • ("[^"]+")第五栏
    • (.*) 其余行
    • echo \x27\1"\x27\x27"\4\x27 保留前四列和第五列之后的其余行,并在日期转换结果中添加双引号
    • $(date -d \3 +%s) 调用带有第五列值的 shell 命令

    请注意,如果输入可以包含单引号,此命令将失败。这可以通过使用s/\x27/\x27\\&\x27/g 来解决。


    您可以使用-n 选项和pe 标志查看执行的命令

    sed -nE '2,$ s/(("[^"]*",){4})("[^"]+")(.*)/echo \x27\1"\x27$(date -d \3 +%s)\x27"\4\x27/pe'
    

    会给

    echo '"58.75","5.33","kg","7","'$(date -d "2020-7-11 19:29:29" +%s)'","5"'
    


    对于58.25,5.89, kg, 7,2020 / 7/12 11:23:46, "5"格式,试试

    sed -E '2,$ s/(([^,]*,){4})([^,]+)(.*)/echo \x27\1\x27$(date -d "\3" +%s)\x27\4\x27/e'
    

    或(改编自https://stackoverflow.com/a/62862416

    awk 'BEGIN{FS=OFS=","} NR>1{$5=mktime(gensub(/[:\/]/, " ", "g", $5))} 1'
    


    注意:对于sed 解决方案,如果输入可能来自外部来源,则必须小心避免cmets 中提到的恶意意图。一种方法是使用[0-9: -]+ 或类似名称匹配第五列。

    【讨论】:

    • 我建议您对照"[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}"(或任何正则表达式以过滤掉$(.*) 和反引号)检查第五个字段。否则,如果该字段包含$(malicious command),则可能会执行某些恶意命令
    • @M.NejatAydin 好点,但我会把它作为 OP 的待办事项 .. 也可以简化为 [0-9: -]+,因为目的是避免恶意命令,任何其他语法问题将被 data 命令覆盖
    • 这将产生单独的进程以在每个输入行调用一次 date - 这是非常低效的,因为它需要 GNU sed 这意味着您也可以访问 GNU awk,我们也可以使用它是内置的时间函数。此外,它容易受到恶意代码注入(尝试在第 5 个字段为 "$(ls)" 的位置添加一行)和变量扩展(尝试将其设置为 "$HOME")。
    • @EdMorton 在答案末尾提到了恶意部分。是的,GNU awk 更适合这里。另外,请注意 OP 更改了输入要求(请参阅已删除的答案)跨度>
    • 啊,我错过了,谢谢你提到它。好吧,无论 OP 决定做什么,希望以后阅读本文的其他人会明白,使用 GNU awk 比使用 GNU sed 可以更快、更健壮地完成这项工作。
    【解决方案2】:

    使用 GNU awk:

    $ gawk '
    BEGIN {
        FS=OFS=","
    }
    {
        n=split($5,a,/[-" :]/)
        if(n==8)
            $5="\"" mktime(sprintf("%s %s %s %s %s %s",a[2],a[3],a[4],a[5],a[6],a[7])) "\""
    }1' file
    

    输出:

    "Weight","Impedance","Units","User","Timestamp","PhysiqueRating"
    "58.75","5.33","kg","7","1594484969","5"
    

    【讨论】:

      【解决方案3】:

      对于 gensub() 和 mktime() 使用 GNU awk:

      $ awk 'BEGIN{FS=OFS="\""} NR>1{$10=mktime(gensub(/[-:]/," ","g",$10))} 1' file
      "Weight","Impedance","Units","User","Timestamp","PhysiqueRating"
      "58.75","5.33","kg","7","1594513769","5"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-03
        • 1970-01-01
        • 2021-12-27
        • 1970-01-01
        • 1970-01-01
        • 2012-05-22
        相关资源
        最近更新 更多