我有一个充满文件的目录,我需要从它们中提取页眉和页脚。它们都是可变长度的,所以使用 head 或 tail 是行不通的。每个文件都有一行我可以搜索,但我不想在结果中包含该行。
通常是
*** Start (more text here)
并以
*** Finish (more text here)
我希望文件名保持不变,所以我需要覆盖原件,或者写入不同的目录,我会自己覆盖它们。
哦,是的,它当然是在 linux 服务器上,所以我有 Perl、sed、awk、grep 等。
试试人字拖!“..“ 操作员。
# 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”。
GNU coreutils 是你的朋友...
csplit inputfile %^\*\*\* Start%1 /^\*\*\* Finish/ %% {*}
这会将您想要的文件生成为xx00. --prefix您可以通过选项、--suffix和更改此行为--digits,但请自行查看手册。由于csplit设计用于生成多个文件,因此无法生成没有后缀的文件,因此您必须手动或通过脚本进行覆盖:
csplit $1 %^\*\*\* Start%1 /^\*\*\* Finish/ %% {*}
mv -f xx00 $1
根据需要添加循环。
要获取标题:
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 手册页。
也许?从不删除开始到完成。
$ sed -i '/^\*\*\* Start/,/^\*\*\* Finish/d!' *
或者......不太确定......但是,如果它有效,也应该删除 Start 和 Finish 行:
$ sed -i -e '/./,/^\*\*\* Start/d' -e '/^\*\*\* Finish/,/./d' *
d!可能取决于sed你的体型——不确定。
而且,我完全是在(可能很差)内存上写的。
一个快速的 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;
覆盖原始文件的 Perl 解决方案。
#!/usr/bin/perl -ni
if(my $num = /^\*\*\* Start/ .. /^\*\*\* Finish/) {
print if $num != 1 and $num + 0 eq $num;
}
perlfaq5中的一些示例:如何在文件中更改、删除或插入一行,或附加到文件的开头?可能会有所帮助。你必须使它们适应你的情况。此外,Leon 的触发器运算符答案是在 Perl 中执行此操作的惯用方式,尽管您不必修改文件即可使用它。