【问题标题】:Split files based on file content and pattern matching根据文件内容和模式匹配拆分文件
【发布时间】:2011-11-26 18:59:04
【问题描述】:

我需要你的帮助来使用 bash/linux 格式化一个 txt 文件。该文件如下所示,它总是有一行名为 Rate: Sth 的行,然后是非常特定格式的详细信息。我想为每个文件以一个速率拆分文件。在这个例子中,我想要 3 个文件,每个文件都有相应的行说明 Rate 值是什么。

您将如何处理?

line No. Main Text
1    Rate: GBP
2    12/01/1999,90.5911501,Validated
     .....
     .....
210  18/01/1999,90.954996,Validated
211  Rate: RMB
212  24/04/2008,132.2542,Validated
     .....
1000 25/04/2008,132.2279,Validated
1001 28/04/2008,131.69915,Validated
1002 Rate: USD
1003 21/11/11,-0.004419534,Validated

【问题讨论】:

  • 只是为了澄清行号不是文件的一部分。
  • 我还希望输出文件包含 Rate: *** 行。

标签: linux perl bash pattern-matching


【解决方案1】:

这可能对你有用:

csplit -z -f 'temp' -b '%02d.txt' file /Rate/ {*}

这将产生文件 temp00.txt、temp01.txt...

如果你只想要Rate 行那么;

sed -i '/Rate/!d' temp*.txt

【讨论】:

    【解决方案2】:

    我会在 perl 中这样做:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    open (my $out, ">-") or die "oops";
    
    while(<>)
    {
        if (m/^Rate: (\w+)/o)
        {
            close $out and open ($out, ">$1") or die "oops";
            next;
        }
    
        print $out $_
    }
    

    像这样使用它

    perl ./test.pl input.txt
    

    【讨论】:

    • 聪明的第一次打开允许简洁的循环。非常好。
    • +1 以获得鼓舞人心的答案。请参阅我对您想法的单行版本的回答。
    【解决方案3】:

    受sehe 回答启发的单线:

    >perl -pwe '
    > if (/^Rate: (.+)/) { 
    >    open $out, ">", "Rate_$1.txt" or die $!; 
    >    select $out; 
    > }' gasdata.txt
    

    -p 选项将在评估 -e 中的代码后读取一行并打印它。 select 将为print 选择默认文件句柄。所以,基本上,我们所做的只是简单地调整文件句柄,这取决于当前哪个 Rate 是活动的。

    下面是被解析的代码:

    >perl -MO=Deparse -pwe 'if (/^Rate: (.+)/) { open $out, ">", "output/Rate_$1.txt" or die $!; select $out; }' gasdata.txt
    BEGIN { $^W = 1; }
    LINE: while (defined($_ = <ARGV>)) {
        if (/^Rate: (.+)/) {
            die $! unless open $out, '>', "output/Rate_$1.txt";
            select $out;
        }
    }
    continue {
        die "-p destination: $!\n" unless print $_;
    }
    -e syntax OK
    

    【讨论】:

      【解决方案4】:

      (g)awk 救援:

      awk '/^Rate:/ {output_file_name=$2; getline } 
           { print $0 >> ( output_file_name ) }' INPUT_FILE
      

      第一个规则和命令对以Rate: 开头的行执行,并且只设置输出文件名,然后从输入文件中获取下一行。然后处理下一行并将其写入输出文件。之后,下一行仅由第二个命令处理(写入输出文件),但前提是它与 Rate: 不匹配。

      注意:如果输入文件中有一个部分包含两个连续的Rate:s 行,则上述解决方案可能会失败,如下所示:

      ... DATA ...
      Rate: GBP
      Rate: CHF
      ... DATA ...
      

      应该这样做(假设行号不是原始文件的一部分)。

      HTH

      【讨论】:

      • 在匹配的模式之后不会只有一行吗?
      • 感谢 Zsolt 的解释。不知道为什么,但我在运行单线时仍然遇到问题。 print $0 &gt;&gt; output_file_name 不应该在output_file_name 周围有"
      【解决方案5】:

      另一种解决方案:它只是将您的输入文件变成一个脚本,然后运行它:

      sed 's/^Rate:/cat <<EOF >/; 1!s/^cat <<EOF/EOF\n&/; $aEOF' input.txt | bash
      

      我假设行号不是文件的一部分。

      【讨论】:

      • 我喜欢这个解决方案!尤其是您使用汇率文本命名文件的方式。一个小问题,但可能会节省一些头发 - 默认情况下,这里的文档将插入变量等 s/^Rate:/cat &lt;&lt;\\EOF &gt;/ 将关闭它。
      • 稍加调整,您也可以拥有Rate... 行。 /^Rate:/{h;s//.../;G};
      【解决方案6】:

      你可以在 perl 中使用类似的东西 -

      Perl 脚本:

      #!/usr/bin/perl
      
      undef $/;
      $_ = <>;
      $n = 0;
      
      for $match (split(/(?=Rate)/)) {
            open(O, '>temp' . ++$n);
            print O $match;
            close(O);
      }
      

      执行:

      [jaypal~/temp]$ ./spl.pl temp.file
      
      [jaypal~/temp]$ **cat temp.file**
      Line No. Main Text
      1    Rate: GBP
      2    12/01/1999,90.5911501,Validated
           .....
           .....
      210  18/01/1999,90.954996,Validated
      211  Rate: RMB
      212  24/04/2008,132.2542,Validated
           .....
      1000 25/04/2008,132.2279,Validated
      1001 28/04/2008,131.69915,Validated
      1002 Rate: USD
      1003 21/11/11,-0.004419534,Validated
      
      [jaypal~/temp]$ cat temp1
      Line No. Main Text
      1    
      
      [jaypal~/temp]$ cat temp2
      Rate: GBP
      2    12/01/1999,90.5911501,Validated
           .....
           .....
      210  18/01/1999,90.954996,Validated
      
      211  
      
      [jaypal~/temp]$ cat temp3
      Rate: RMB
      212  24/04/2008,132.2542,Validated
           .....
      1000 25/04/2008,132.2279,Validated
      1001 28/04/2008,131.69915,Validated
      
      1002 [jaypal~/temp]$ cat temp4
      Rate: USD
      1003 21/11/11,-0.004419534,Validated
      [jaypal~/temp]$ 
      

      【讨论】:

        猜你喜欢
        • 2017-04-27
        • 1970-01-01
        • 1970-01-01
        • 2012-01-14
        • 1970-01-01
        • 2015-11-14
        • 1970-01-01
        • 2011-08-20
        • 1970-01-01
        相关资源
        最近更新 更多