首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Perl脚本删除文件中的重复标题/预告片

Perl脚本删除文件中的重复标题/预告片
EN

Unix & Linux用户
提问于 2023-02-28 05:14:29
回答 2查看 113关注 0票数 2

我已经创建了一个perl脚本,将10个文件合并到一个文件中。每个文件中都有关键字标题/拖车。因此合并文件有多个标头和预告片关键字。但是我要求标题和预告片只出现在合并文件的开始和结束。

示例:

File1.txt ->

代码语言:javascript
运行
复制
Header
Content1
Trailer

File2.txt -->

代码语言:javascript
运行
复制
Header
Content2
Trailer

Merged.txt (目前)->

代码语言:javascript
运行
复制
Header
Content1
Trailer
Header
Content2
Trailer

Merged.txt (必需)->

代码语言:javascript
运行
复制
Header
Content1
Content2
Trailer
EN

回答 2

Unix & Linux用户

发布于 2023-02-28 05:22:27

试着做这样的事情:

代码语言:javascript
运行
复制
perl -ne 'if ($. == 1 || eof) { print ; next };
          print unless /Header|Trailer/' merged.txt

这应该打印第一行和最后一行,无论内容,以及每一行不包含标题或挂载。

如果您希望使用perl的-i选项来修改输入文件而不是打印到stdout (但是,您知道,我建议在验证输出是否符合您的要求之后才建议这样做--例如,重定向到另一个文件并使用diff与原始文件进行比较)。

只要稍加修改,这也可用于连接任意数量的输入文件,删除任何“头”或“拖车”行,同时仍然确保始终打印第一行文件和最后一行文件(即使其中包含“标头”或“拖车”)。例如:

代码语言:javascript
运行
复制
$ 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-ed,从而减少计数。最后一个文件的结果是0 (false)。在读取最后一个文件时,用!否定这一点会导致true。如果使用eof (如果我们是当前文件的末尾,则为true ),那么只有在最后一个文件的最后一行上才是true。

如果这些条件之一为真,则打印当前行。

第二条语句打印当前行,除非它与“标头”或“拖车”匹配。

顺便说一句,unless是一种与if ! (“如果不是”)等价的perl语法--有时说“如果不是X就做Y”更自然,而其他时候更自然地说“做Y除非X”。两者在功能上是相同的。这两种方法都可以放在要有条件执行的语句之前或之后。您可能会猜到perl的主要设计人员&作者(Larry )是语言学家。

来自man perlsyn

if只在条件为真的情况下执行一次语句。unless正好相反,它执行语句,除非条件为true (也就是说,如果条件为false)。

严格来说,第一个条件中的{print; next}并不是必需的--如果第一行或最后一行<#>不包含"Header“或”拖车“,则防止第一行或最后一行被打印两次。如果您确信永远不会发生这种情况,则可以将第一条语句简化为:

对于第一个-班轮:

代码语言:javascript
运行
复制
print if ($. == 1 || eof);

或者(对于第二条班轮):

代码语言:javascript
运行
复制
print if ($. == 1 || (! @ARGV && eof));
票数 2
EN

Unix & Linux用户

发布于 2023-02-28 05:56:00

我会这样做:

代码语言:javascript
运行
复制
perl -i -lne 'print unless ($_ eq "Header" && $. > 1) || ($_ eq "Trailer" && !eof)' your-file

也可以用sed完成:

代码语言:javascript
运行
复制
sed -e 1b -e '$b' -e '/^Header$/d' -e '/^Trailer$/d' your-file

一些sed实现可以进行perl风格的内部编辑,有些(大部分)可以使用-i,有些(FreeBSD和派生工具,包括macos)可以使用-i ''

您可以在合并时删除冗余的报头/拖车:

代码语言:javascript
运行
复制
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.txt排序的n上进行数字匹配(因此file10.txtfile9.txtfile11.txt之间进行排序,而不是在file1.txtfile2.txt之间排序,否则)需要zsh shell)

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

代码语言:javascript
运行
复制
() {
  head -n1 < $1
  sed -s -- '1d;$d' "$@"
  tail -n1 < $argv[-1]
} file<->.txt(n)
票数 2
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/737166

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档