在Linux命令行中使用sed,awk或其他方式从文本文件生成csv

时间:2019-05-22 19:21:09

标签: awk sed csh

我有一个包含数千行的文件,我希望将其作为csv以便以后处理。

原始文件如下:

cc_1527 (ILDO_I173_net9 VSSA) capacitor_mis c=9.60713e-16
cc_1526 (VDD_MAIN Istartupcomp_I115_G7) capacitor_mis \
    c=4.18106e-16
cc_1525 (VDD_MAIN Istartupcomp_I7_net025) capacitor_mis \
    c=9.71462e-16
cc_1524 (VDD_MAIN Istartupcomp_I7_ST_net14) \
    capacitor_mis c=4.6011e-17
cc_1523 (VDD_MAIN Istartupcomp_I7_ST_net15) \
    capacitor_mis c=1.06215e-15
cc_1522 (VDD_MAIN ILDO_LDO_core_Istartupcomp_I7_ST_net16) \
    capacitor_mis c=1.37289e-15
cc_1521 (VDD_MAIN ILDO_LDO_core_Istartupcomp_I7_I176_G4) capacitor_mis \
    c=6.81758e-16

这里的问题是某些行继续到下一行,用符号“ \”表示。

原始文本前5行的最终csv格式应为:

cc_1527,(ILDO_I173_net9 VSSA),capacitor_mis c=9.60713e-16
cc_1526,(VDD_MAIN Istartupcomp_I115_G7),capacitor_mis,c=4.18106e-16
cc_1525,(VDD_MAIN Istartupcomp_I7_net025),capacitor_mis,c=9.71462e-16

因此,现在所有内容仅在一行中,并且已删除“ \”字符。

请注意,每行的开头可能存在空格,因此在执行其他任何操作之前应将其修剪掉。

关于如何完成此操作的任何想法。 ?

谢谢。

最好的问候, 佩德罗

2 个答案:

答案 0 :(得分:1)

使用sed的一些较晦涩的功能(它可以做的s///以外):

$ sed -E ':line /\\$/ {s/\\$//; N; b line}; s/[[:space:]]+/,/g' demo.txt
cc_1527,(ILDO_I173_net9,VSSA),capacitor_mis,c=9.60713e-16
cc_1526,(VDD_MAIN,Istartupcomp_I115_G7),capacitor_mis,c=4.18106e-16
cc_1525,(VDD_MAIN,Istartupcomp_I7_net025),capacitor_mis,c=9.71462e-16
cc_1524,(VDD_MAIN,Istartupcomp_I7_ST_net14),capacitor_mis,c=4.6011e-17
cc_1523,(VDD_MAIN,Istartupcomp_I7_ST_net15),capacitor_mis,c=1.06215e-15
cc_1522,(VDD_MAIN,ILDO_LDO_core_Istartupcomp_I7_ST_net16),capacitor_mis,c=1.37289e-15
cc_1521,(VDD_MAIN,ILDO_LDO_core_Istartupcomp_I7_I176_G4),capacitor_mis,c=6.81758e-16

基本上:

  • 在模式空间中读取一行。

  • :line /\\$/ {s/\\$//; N; b line}:如果模式空间以\结尾,请删除该反斜杠,阅读下一行并将其追加到模式空间,然后重复此步骤。

  • s/[[:space:]]+/,/g:将每种情况下的1个或多个空格字符转换为单个逗号。

  • 打印结果,并以新行返回到开头。

答案 1 :(得分:1)

@Shawn的答案已被OP接受,我不确定 如果我的答案值得发布,但请允许我仅供参考。 如果您选择Perl,请尝试以下脚本,该脚本会保留 括号内的空格不能用逗号代替:

perl -0777 -ne '
    s/\\\n//g;
    foreach $line (split(/\n/)) {
        while ($line =~ /(\([^)]+\))|(\S+)/g) {
            push(@ary, $&);
        }
        print join(",", @ary), "\n";
        @ary = ();
    }
' input.txt

输出:

cc_1527,(ILDO_I173_net9 VSSA),capacitor_mis,c=9.60713e-16
cc_1526,(VDD_MAIN Istartupcomp_I115_G7),capacitor_mis,c=4.18106e-16
cc_1525,(VDD_MAIN Istartupcomp_I7_net025),capacitor_mis,c=9.71462e-16
cc_1524,(VDD_MAIN Istartupcomp_I7_ST_net14),capacitor_mis,c=4.6011e-17
cc_1523,(VDD_MAIN Istartupcomp_I7_ST_net15),capacitor_mis,c=1.06215e-15
cc_1522,(VDD_MAIN ILDO_LDO_core_Istartupcomp_I7_ST_net16),capacitor_mis,c=1.37289e-15
cc_1521,(VDD_MAIN ILDO_LDO_core_Istartupcomp_I7_I176_G4),capacitor_mis,c=6.81758e-16

[工作原理]

  • 首先,-0777 -ne选项告诉Perl吞下所有行 进入Perl的默认变量$_
  • 接下来,s/\\\n//g;通过合并行来删除结尾的反斜杠。
  • 然后split(/\n/)再次将换行符拆分为行。
  • 正则表达式/(\([^)]+\))|(\S+)/g将是最重要的部分 将每一行划分为多个字段。字段模式定义为: "substring surrounded by parens OR substring which does not include whitespaces."FPAT中用作awk,并保留空格 在两个括号之间,而不必在其上划分线。

我测试了大约10,000行输入和执行时间 不到一秒钟。
希望这会有所帮助。