【问题标题】:How can I extract lines of text from a file?如何从文件中提取文本行?
【发布时间】:2010-09-22 17:17:54
【问题描述】:

我有一个充满文件的目录,我需要从它们中提取页眉和页脚。它们都是可变长度的,所以使用 head 或 tail 是行不通的。每个文件都有一行我可以搜索,但我不想在结果中包含该行。

通常是

*** Start (more text here)

结尾
*** Finish (more text here)

我希望文件名保持不变,所以我需要覆盖原始文件,或者写入不同的目录,我会自己覆盖它们。

哦,是的,它当然是在 linux 服务器上,所以我有 Perl、sed、awk、grep 等。

【问题讨论】:

    标签: regex perl sed awk grep


    【解决方案1】:

    也许?从不删除开始到结束。

    $ sed -i '/^\*\*\* Start/,/^\*\*\* Finish/d!' *
    

    或者...不太确定...但是,如果可行,也应该删除 Start 和 Finish 行:

    $ sed -i -e '/./,/^\*\*\* Start/d' -e '/^\*\*\* Finish/,/./d' *
    

    d! 可能取决于您拥有的sed 的构建——不确定。
    而且,我完全是在(可能很差)记忆力上写的。

    【讨论】:

      【解决方案2】:

      获取标题

      cat yourFileHere | awk '{if (d > 0) print $0} /.*Start.*/ {d = 1}'
      

      获取页脚

      cat yourFileHere | awk '/.*Finish.*/ {d = 1} {if (d < 1) print $0}'
      

      根据需要从页眉到页脚获取文件:

      cat yourFileHere | awk '/.*Start.*/ {d = 1; next} /.*Finish.*/ {d = 0; next} {if (d > 0) print $0}'
      

      还有另一种方法,使用 csplit 命令,您应该尝试以下操作:

      csplit yourFileHere /Start/ /Finish/
      

      并检查名为“xxNN”的文件,其中 NN 是运行号,还请查看csplit manpage

      【讨论】:

      • 如果我没有指出对 cat 的不必要使用,那我就失职了。 awk 'code' 文件名更容易输入。 :)
      【解决方案3】:

      快速 Perl hack,未经测试。我在 sed 或 awk 方面不够流利,无法通过它们获得这种效果,但我会对如何做到这一点感兴趣。

      #!/usr/bin/perl -w
      use strict;
      use Tie::File;
      my $Filename=shift;  
      tie my @File, 'Tie::File', $Filename or die "could not access $Filename.\n";  
      while (shift @File !~ /^\*\*\* Start/) {};  
      while (pop @File !~ /^\*\*\* Finish/) {};  
      untie @File;  
      

      【讨论】:

        【解决方案4】:

        覆盖原始文件的 Perl 解决方案。

        #!/usr/bin/perl -ni
        if(my $num = /^\*\*\* Start/ .. /^\*\*\* Finish/) {
            print if $num != 1 and $num + 0 eq $num;
        }
        

        【讨论】:

          【解决方案5】:

          试试flip flop! ".." 运算符。

          # flip-flop.pl
          use strict;
          use warnings;
          
          my $start  = qr/^\*\*\* Start/;
          my $finish = qr/^\*\*\* Finish/;
          
          while ( <> ) {
              if ( /$start/ .. /$finish/ ) {
                  next  if /$start/ or /$finish/;
                  print $_;
              }
          }
          

          然后你可以使用 -i perl 开关来更新你的文件,就像这样.....

           $ perl -i'copy_*' flip-flop.pl data.txt 
          

          ...它会更改 data.txt,但会事先将副本复制为“copy_data.txt”。

          【讨论】:

          • 如何让这个(触发器/范围运算符)使用变量而不是从文件中读取。假设我有一个 $variable = "dont want this part START i want this part instead FINISH"; ?因为当它是一个变量而不是文件时,我无法获得相同的效果,非常感谢您的帮助,谢谢 –
          【解决方案6】:

          perlfaq5: How do I change, delete, or insert a line in a file, or append to the beginning of a file? 中的一些示例可能会有所帮助。你必须使它们适应你的情况。此外,Leon 的触发器运算符答案是在 Perl 中执行此操作的惯用方式,尽管您不必修改文件即可使用它。

          【讨论】:

            【解决方案7】:

            GNU coreutils 是你的朋友...

            csplit inputfile %^\*\*\* Start%1 /^\*\*\* Finish/ %% {*}
            

            这会生成您想要的文件为xx00。您可以通过选项--prefix--suffix--digits 更改此行为,但请自行查看manual。由于csplit 设计用于生成多个文件,因此无法生成没有后缀的文件,因此您必须手动或通过脚本进行覆盖:

            csplit $1 %^\*\*\* Start%1 /^\*\*\* Finish/ %% {*}
            mv -f xx00 $1
            

            根据需要添加循环。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-02-05
              • 2016-04-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多