Perl 脚本删除文件中重复的标题/尾部

Perl 脚本删除文件中重复的标题/尾部

我创建了一个 perl 脚本来将 10 个文件合并为一个。每个文件在文件中都有关键字标题/预告片。因此合并的文件有多个 header 和 Trailer 关键字。但我要求标题和预告片仅出现在合并文件的开头和结尾中。

例子:

文件1.txt -->

Header
Content1
Trailer

文件2.txt -->

Header
Content2
Trailer

Merged.txt(当前)-->

Header
Content1
Trailer
Header
Content2
Trailer

Merged.txt(必需)-->

Header
Content1
Content2
Trailer

答案1

我会做:

perl -i -lne 'print unless ($_ eq "Header" && $. > 1) || ($_ eq "Trailer" && !eof)' your-file

也可以通过以下方式完成sed

sed -e 1b -e '$b' -e '/^Header$/d' -e '/^Trailer$/d' your-file

一些sed实现可以进行 perl 风格的就地编辑,一些(大多数)使用-i,一些(FreeBSD 和衍生品,包括 macos)使用-i ''

您可以在合并时删除多余的标题/结尾:

perl -lne '
  if (eof) {
    $n++;  # counts files
    close ARGV; # resets $.
    next if @ARGV; # if there are more files to process
  }
  print unless $. == 1 && $n # first list and not first file
  ' file<->.txt(n)

file<->.txt(n)要匹配按数字file<number>.txt排序n(因此在和file10.txt之间排序)file9.txtfile11.txt,而不是在file1.txt和之间file2.txt排序)需要zshshell)

或者使用 GNU sed(仍然zsh):

() {
  head -n1 < $1
  sed -s -- '1d;$d' "$@"
  tail -n1 < $argv[-1]
} file<->.txt(n)

答案2

尝试这样的事情:

perl -ne 'if ($. == 1 || eof) { print ; next };
          print unless /Header|Trailer/' merged.txt

无论内容如何,​​都应该打印第一行和最后一行,以及不包含标题或尾部的每一行。

如果您希望它修改输入文件而不是打印到标准输出,请使用 perl 的-i选项(但是,您知道,我不建议这样做,直到验证输出是您想要的 - 例如重定向到另一个文件并使用diff比较与原文)。


通过小的修改,这也可以用于连接任意数量的输入文件,删除任何“标题”或“尾部”行,同时仍然确保第一个文件的第一行和最后一个文件的最后一行始终是打印(即使它们包含“标题”或“预告片”)。例如:

$ perl -ne 'if ($. == 1 || (! @ARGV && eof)) { print ; next };
            print unless /Header|Trailer/' file1.txt file2.txt 
Header
Content1
Content2
Trailer

第一个语句测试两个条件:

  1. $. == 1测试当前行是否是第一输入行

  2. (! @ARGV && eof)测试当前行是否是最后一个文件的最后一行。

    在标量上下文中求值@ARGV会返回命令行参数(文件名)数组中的元素数量,并且每个文件名shift在打开进行处理时都会从数组中删除,从而减少计数。最后一个文件的结果将为 0(假)。否定这一点!读取最后一个文件时,

    AND 运算eof(如果是当前文件的末尾则为 true)仅在最后一个文件的最后一行为 true。

如果其中一个条件为真,则打印当前行。

第二条语句打印当前行,除非它与“Header”或“Trailer”匹配。

BTW,unlessperl 语法相当于if !(“if not”) - 有时更自然地说“如果不是 X,则执行 Y”,其他时候更自然地说“执行 Y,除非 X”。两者在功能上是相同的。两者都可以放置在要有条件执行的语句之前或之后。您可能会猜到 Perl 的主要设计者和作者(Larry Wall)是一位语言学家。

man perlsyn

if当且仅当条件为真时才执行该语句一次。

unless反之,除非条件为真(即条件为假),否则它会执行语句。


{print; next}一个条件中的 并不是严格必要的 - 它是为了防止第一行或最后一行被打印两次(如果它们)包含“标题”或“预告片”。如果您确定永远不会出现这种情况,则第一个语句可以稍微简化为:

对于第一个单行:

print if ($. == 1 || eof);

或(对于第二行):

print if ($. == 1 || (! @ARGV && eof));

相关内容