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

Generating csv from text file in Linux command line with sed, awk or other

我有一个包含数千行的文件,我想将其保存为 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

所以,现在所有内容都在一行中,并且“\”字符已被删除。

请注意每行的开头可能存在空格,因此在执行任何其他操作之前应先删除这些空格。

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

提前致谢。

此致, 佩德罗

使用 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

基本上:

  • 将一行读入模式space。

  • :line /\$/ {s/\$//; N; b line}:如果模式 space 以 \ 结尾,删除反斜杠,读取下一行并将其附加到模式 space,重复此步骤。

  • s/[[:space:]]+/,/g: 将 1 个或多个白色 space 字符的每个大小写转换为单个逗号。

  • 打印结果,换行回到开头

@Shawn 的回答已被 OP 接受,我不确定 如果我的回答值得发布,但请允许我这样做仅供参考。 如果 Perl 是您的选择,请尝试以下保留的脚本 parens 中的空格不替换为逗号:

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." 它作为 FPATawk 中工作并保留空格 在 parens 之间不分界线。

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