Linux单行命令:在大文件最后一个.Ends前插入指定行
问题:在大文件最后一处
.Ends前插入内容 我有一个约1.5GB的大型文本文件,其中包含多行以.Ends结尾的内容。需要编写一条Linux单行命令(可使用Perl/Awk/Sed),找到文件中最后一处.Ends的出现位置,并在其前方插入若干行。
我尝试过用tac结合Perl的方法,但都遇到了问题:
- 命令1:
tac ../../test | perl -pi -e 'BEGIN {$flag = 1} if ($flag==1 && /.Ends/) {$flag = 0 ; print "someline\n"}' | tac
结果:插入的内容出现在.Ends之后,显示为:… .Ends someline - 命令2:
tac ../../test | perl -e 'BEGIN {$flag = 1} print ; if ($flag==1 && /.Ends/) {$flag = 0 ; print "someline\n"}' | tac
结果:无任何输出 - 命令3:
tac ../../test | perl -p -e 'BEGIN {$flag = 1} print $_ ; if ($flag==1 && /.Ends/) {$flag = 0 ; print "someline\n"}' | tac
结果:所有内容重复输出,显示为:… .Ends someline .Ends
额外需求:若插入的内容可来自其他文件则更佳(非必需)。
测试输入文件:
gla2 fla3 dla4 rfa5 .Ends shu sha she .Ends res pes ges .Ends
期望输出:
gla2 fla3 dla4 rfa5 .Ends shu sha she .Ends res pes ges someline .Ends # * some irrelevant junk * #
解决方案
方法1:Perl + tac(内存友好,适合大文件)
利用tac反转文件,找到第一个出现的.Ends(对应原文件最后一个),先打印插入内容再打印该行,最后反转回去。
插入单行内容:
tac ../../test | perl -pe 'BEGIN {$flag=1} if ($flag && /.Ends/) {print "someline\n"; $flag=0}' | tac
从文件读取插入内容(比如insert.txt):
tac ../../test | perl -pe ' BEGIN { $flag=1; open my $fh, "<", "insert.txt"; $insert = do { local $/; <$fh> }; # 一次性读取整个插入文件内容 } if ($flag && /.Ends/) { print $insert; $flag=0; } ' | tac
方法2:Awk方案(无需tac,适合内存充足场景)
将文件所有行存入数组,记录最后一个.Ends的位置,然后重新输出时在该位置前插入内容。
插入单行内容:
awk ' { lines[NR] = $0 } /.Ends/ { last_end = NR } END { for (i=1; i<=last_end-1; i++) print lines[i] print "someline" for (i=last_end; i<=NR; i++) print lines[i] } ' ../../test
从文件读取插入内容:
awk ' BEGIN { # 读取插入文件内容 while ((getline line < "insert.txt") > 0) { insert = insert line "\n" } } { lines[NR] = $0 } /.Ends/ { last_end = NR } END { for (i=1; i<=last_end-1; i++) print lines[i] printf "%s", insert for (i=last_end; i<=NR; i++) print lines[i] } ' ../../test
之前命令的问题分析
- 命令1用了
-pi参数,-i是原地修改文件,在管道中无效;且逻辑是先打印插入内容再打印当前行,反转后插入内容就到了.Ends后面。 - 命令2没有用
-p/-n参数,print无指定输出内容,所以没有输出。 - 命令3中手动
print $_加上-p自动打印每行,导致每行被重复输出,出现两次.Ends。
内容的提问来源于stack exchange,提问作者user2141046
相关产品推荐
相关产品推荐

