【问题标题】:Reformat date in text file (.csv) with sed and date使用 sed 和日期重新格式化文本文件 (.csv) 中的日期
【发布时间】:2018-03-28 15:58:09
【问题描述】:

这是输入的 .csv 文件

"item1","10/11/2017 2:10pm",1,2, ...
"item2","10/12/2017 3:10pm",3,4, ...
.
.
.

现在,我想将第二列(日期)转换为这种特定格式 date -d '10/12/2017 2:10pm' +'%Y/%m/%d %H:%M:%S',以便 "10/12/2017 2:10pm" 转换为 "2017/10/12 14:10:00"

期待输出文件

"item1","2017/10/11 14:10:00",1,2, ...
"item2","2017/10/12 15:10:00",3,4, ...
.
.
.

我知道可以使用 bash 或 python 来完成,但我想在 单行命令 中完成。有任何想法吗?有没有办法将date 结果传递给sed

【问题讨论】:

  • @MarcLambrichs,OP 没有提到awk,那么为什么要添加那个标签呢?
  • 因为 OP 声明 我想在单行命令中完成。有什么想法吗?。这就是为什么。
  • @agc awk 是解决此类问题的有效工具。添加标签吸引了更多的答案,这有利于OP。
  • @MarcLambrichs 我更喜欢你的回答,但我现在找不到。

标签: shell datetime awk sed command-line


【解决方案1】:

修改了不那么丑的sed方法:

sed 's/^.*,"\|",.*//g;h;s#.*#date "+%Y/%m/%d %T" -d "&"#e;H;g;s#\n\|$#,#g;s/^/s,/' input.csv | sed -f - input.csv 

展开,(它的工作原理相同):

sed 's/^.*,"\|",.*//g
     h;
     s#.*#date "+%Y/%m/%d %T" -d "&"#e;
     H;
     g;
     s#\n\|$#,#g;
     s/^/s,/' input.csv | sed -f - input.csv 

输出:

"item1","2017/10/11 14:10:00",1,2, ...
"item2","2017/10/12 15:10:00",3,4, ...

它是如何工作的:

第一个sed 块使用e评估命令运行date,其输出用于生成一些新的sed s替换命令。要显示新的 s 命令,请暂时将 shell 脚本 | 管道替换为 # 注释:

s,10/11/2017 2:10pm,2017/10/11 14:10:00,
s,10/12/2017 3:10pm,2017/10/12 15:10:00,

这些通过管道传送到第二个sed

【讨论】:

  • 我认为解决这个问题的任何一种方法都不会“漂亮”,但我喜欢你和 Marc 的解决方案,甚至是带有 5 个子表达式的 sed 或单个 @ 987654333@ 解决方案可能比两者的结合更快。
  • @DavidC.Rankin,生成蛮力代码的代码通常不会太快,但有时编码更容易/更快。但这与 OP 关于如何通过 sed (或 GNU sed 无论如何)运行 date 的问题有关。我想我的printf 可以删除(以及date 周围的反引号),更有效地使用sed 命令...
  • 我怀疑你是对的。我宁愿单独调用sedawk 而不是混合蛮力方法。我仍在修补 awk 以摆脱 expr。但是由于我们知道它始终是第二个字段,单个 sed 查找第一个 ," 并捕获 \([^"]*\) 作为反向引用将处理然后只需转换为新日期格式并替换到位。真是单线……
  • 这真是一门艺术!我要学的东西太多了。谢谢。
  • @agc 一个小修复,在s#.*#date "+%Y/%M/%d %T" -d &#e; %M 应该改为%m
【解决方案2】:

你可以在一行中完成,但这引出了一个问题——“你想要多长的一行?”由于您将其标记为 'shell' 而不是 bash 等,因此您的字符串处理有点受限。 POSIX shell 提供了足够的能力来做你想做的事,但这并不是最快的补救措施。您要么最终得到一个调用 dateawksed 解决方案,要么是调用 awksed 的 shell 解决方案来解析原始文件中的旧日期并将结果提供给 @987654327 @得到你的新约会。您必须找出最有效的补救措施。

就单线而言,您可以在保持 POSIX 兼容的同时执行类似于以下的操作。它只是使用awk 从文件中获取第二个field,将结果通过管道传输到while 循环,该循环使用expr length "$field" 来获取长度并在expr substr "$field" "2" <length expression - 2> 中使用它来从原始日期结束 olddt,然后是 date -d "$olddt" +'%Y/%m/%d %H:%M:%S' 以获取 newdt,最后是 sed -i "s;$olddt;$newdt;" 以执行替换。您的单行(显示为便于阅读,自动续行)

$ awk -F, '{print $2}' timefile.txt | 
while read -r field; do 
olddt="$(expr substr "$field" "2" "$(($(expr length "$field") - 2))")"; 
newdt=$(date -d "$olddt" +'%Y/%m/%d %H:%M:%S'); 
sed -i "s;$olddt;$newdt;" timefile.txt; done

输入文件示例

$ cat timefile.txt
"item1","10/11/2017 2:10pm",1,2, ...
"item2","10/12/2017 3:10pm",3,4, ...

结果文件

$ cat timefile.txt
"item1","2017/10/11 14:10:00",1,2, ...
"item2","2017/10/12 15:10:00",3,4, ...

可能有更快的方法来做到这一点,但这是一个合理的长度单行(相对而言)。

【讨论】:

    【解决方案3】:

    单线awk 方法。

    awk -F',' '{gsub(/"/,"",$2); cmd="date -d\""$2"\" +\\\"%Y/%m/%d\\ %T\\\"";
        cmd |getline $2; close(cmd) }1' OFS=, infile #>>outfile
    "item1","2017/10/11 14:10:00",1,2, ...
    "item2","2017/10/12 15:10:00",3,4, ...
    

    这将在您的终端中输出更改,如果您需要记录输出,则需要将输出重定向到文件或使用 FILENAME 将输出重定向到输入 infile 本身。

    awk -F',' '{gsub(/"/,"",$2); cmd="date -d\""$2"\" +\\\"%Y/%m/%d\\ %T\\\"";
        cmd |getline $2; close(cmd); print >FILENAME }' OFS=, infile
    

    或者使用 GNU awk 实现,它支持 -i inplace 标识符进行就地替换。见'awk' save modifications in place

    【讨论】:

    • 但是,你确实有一个大问题。您正在丢失字段周围的引号。看看能不能改正。
    • @ClintonLam 不,这适用于名为 infile 的文件。我自己检查过。关于引号,我不介意,因为您的 csv 似乎没有。如果是这样,则可以解决此问题。 αғsнιη,把它拿走。
    • "item1","10/11/2017 2:10pm",77.300,14127044,23190700,77.700,77.320,77.300,77.750,56.600,79.650,76.127,71.239,142.415,36.709,0.000,,1575.53B,"A" "item2","10/12/2017 3:10pm",192.200,614721,942324,190.800,190.400,190.100,192.200,136.200,195.300,183.516,168.717,23.157,12.046,0.000,,367.49B,"B" 在这组文本上失败,这里只有两行,第二行的日期没有被替换。
    • 请查看我的更新,@DavidC.Rankin 已更正。
    • @αғsнιη 干得好。这将比混合 shell、awk、sed 解决方案更有效。我必须更多地使用 awk...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    • 1970-01-01
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多