我有一个巨大的文本文件(~ 1. 5GB),其中有许多行以“.Ends”结尾。
我需要一个linux oneliner(perl\ awk\ sed)来找到最后的地方'.Ends'出现在文件中,并在它之前添加几行。
我尝试使用tac
两次,但遇到了Perl:
当我用途:tac ../../test | perl -pi -e 'BEGIN {$flag = 1} if ($flag==1 && /.Ends/) {$flag = 0 ; print "someline\n"}' | tac
它首先打印“someline\n”,然后才打印。Ends结果为:
...
.结束
索梅林
当我用途:tac ../../test | perl -e 'BEGIN {$flag = 1} print ; if ($flag==1 && /.Ends/) {$flag = 0 ; print "someline\n"}' | tac
它什么都不打印。
当我用途:tac ../../test | perl -p -e 'BEGIN {$flag = 1} print $_ ; if ($flag==1 && /.Ends/) {$flag = 0 ; print "someline\n"}' | tac
它会打印所有内容两次:
...
.结束
索梅林
.结束
是否有一种流畅的方法来执行此编辑?
不必跟我解方向,我不挑剔......
奖金-如果行可以来自不同的文件,这将是伟大的(但真的不是必须的)
- 编辑 *
测试输入文件:
gla2
fla3
dla4
rfa5
.Ends
shu
sha
she
.Ends
res
pes
ges
.Ends
--->
...
pes
ges
someline
.Ends
# * some irrelevant junk * #
6条答案
按热度按时间r1zk6ea11#
假设该短语的最后一个示例位于文件的最下面,那么从后面处理文件(例如使用File::ReadBackwards)将极大地提高性能。
由于您需要在最后一个标记之前添加其他文本到文件中,因此我们必须复制它的其余部分,以便能够在添加后将其放回。
在最后一个
.Ends
之前添加的新文本可能在文件add.txt
中。问题是最后一个
.Ends
标记之后还有多少文件?我们将所有文件复制到内存中,以便能够将其写回。如果太多,则将其复制到临时文件而不是内存中,然后从那里使用并删除该文件。eanckbw92#
使用GNU
sed
,-i.bak
将创建一个扩展名为.bak
的备份文件,同时就地保存原始文件tjrkku2a3#
输入:
一个与OP的
tac | <process> | tac
方法一致的awk
想法:awk
的另一个想法是用输入文件的双遍调用代替双tac
调用:备注:
test.dat
)agxfikkp4#
由于您要从文件中读取新行:
第一个
上面假设在你的示例输入中的某些行
.Ends
后面的白色是错误的。如果它们确实存在,那么将$0==".Ends"
更改为/^\.Ends[[:space:]]*$/
,或者如果在这些行上也可能有前导空格,则将/^[[:space:]]*\.Ends[[:space:]]*$/
更改为/\.Ends/
,或者如果在.Ends
之前/之后可以有任何字符,则将/\.Ends/
更改为.Ends
。pb3skfrl5#
输入:
一种
ed
方法:或者作为一句俏皮话:
其中:
>/dev/null 2>&1
-强力抑制诊断和信息消息1
-转到第1行?.Ends
-在文件中向后搜索字符串.Ends
(即,在文件中查找最后一个.Ends
)-1r new.dat
-在文件中向后/向上移动1行(-1
),并在new.dat
的内容中读取r
wq
-w
写入与q
退出(也称为保存与退出)这会产生:
**注意:**与OP的当前代码(将修改的数据写入stdout)不同,此解决方案修改原始输入文件(
test.dat
)h9vpoimq6#
首先让
grep
进行搜索,然后将awk
注入行。数据