我已经创建了一个perl脚本,将10个文件合并到一个文件中。每个文件中都有关键字标题/拖车。因此合并文件有多个标头和预告片关键字。但是我要求标题和预告片只出现在合并文件的开始和结束。
示例:
File1.txt ->
Header
Content1
Trailer
File2.txt -->
Header
Content2
Trailer
Merged.txt (目前)->
Header
Content1
Trailer
Header
Content2
Trailer
Merged.txt (必需)->
Header
Content1
Content2
Trailer
发布于 2023-02-28 05:22:27
试着做这样的事情:
perl -ne 'if ($. == 1 || eof) { print ; next };
print unless /Header|Trailer/' merged.txt
这应该打印第一行和最后一行,无论内容,以及每一行不包含标题或挂载。
如果您希望使用perl的-i
选项来修改输入文件而不是打印到stdout (但是,您知道,我建议在验证输出是否符合您的要求之后才建议这样做--例如,重定向到另一个文件并使用diff
与原始文件进行比较)。
只要稍加修改,这也可用于连接任意数量的输入文件,删除任何“头”或“拖车”行,同时仍然确保始终打印第一行文件和最后一行文件(即使其中包含“标头”或“拖车”)。例如:
$ perl -ne 'if ($. == 1 || (! @ARGV && eof)) { print ; next };
print unless /Header|Trailer/' file1.txt file2.txt
Header
Content1
Content2
Trailer
第一个语句测试两个条件:
$. == 1
测试当前行是否是第一个输入行(! @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“或”拖车“,则防止第一行或最后一行被打印两次。如果您确信永远不会发生这种情况,则可以将第一条语句简化为:
对于第一个-班轮:
print if ($. == 1 || eof);
或者(对于第二条班轮):
print if ($. == 1 || (! @ARGV && eof));
发布于 2023-02-28 05:56:00
我会这样做:
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.txt
排序的n
上进行数字匹配(因此file10.txt
在file9.txt
和file11.txt
之间进行排序,而不是在file1.txt
和file2.txt
之间排序,否则)需要zsh
shell)
或者使用GNU sed
(仍然是zsh
):
() {
head -n1 < $1
sed -s -- '1d;$d' "$@"
tail -n1 < $argv[-1]
} file<->.txt(n)
https://unix.stackexchange.com/questions/737166
复制相似问题