给定一个包含以下内容的文件:
<root>
<a></a>
<b></b>
</root>
命令应输出:
<root>
<a></a>
<b></b>
我尝试使用GNU Win32
的{{1}}端口尝试的内容:
删除最后两行。
这很快,但它假设sed
是倒数第二行,如果不是则会导致错误。
</root>
用空字符串替换所有出现的sed -e '$d' test.xml | sed -e '$d'
。
这样可行,但比第一个解决方案慢,如果有嵌套的</root>
元素(不太可能),它将会中断。
<root>
我正在处理的文件可能很大,因此效率非常重要。
有没有办法将sed替换限制在文件的最后一次出现?或者是否有其他更快的实用程序?
答案 0 :(得分:2)
使用Perl和File :: Backwards应该非常快(相对,我知道,但仍然......)。 Perlfaq5有a topic向后浏览文件并删除行。您可以使用此主题的代码作为起点来检查您的模式。
答案 1 :(得分:1)
使用sed
:
sed -e ':a;N;$!ba;s|\(.*\)</root>\n\(.*\)|\1\2|'
答案 2 :(得分:1)
如何使用awk
。
awk '/^<\/root>$/{next}/<\/root>/{sub(/<\/root>/,"");print;next}1' filename
第一个 /pattern/{action}
语句会查找仅 </root>
的行。它模式找到它,动作忽略它。
第二个 /pattern/{action}
语句会在该行中查找包含</root>
任何地方的行。如果模式找到它,sub function
将其替换为空,并打印其余部分。
第三次 操作1
对于其中没有模式</root>
的所有行都是如此。如果找到它,它会打印出来。
我做了一个快速测试,这就是结果 -
<强>测试强>
[jaypal:~/Temp] cat tmp
<root>
<a></a>
<b></b>
</root>
<root>
<a></a>
<b></b>
</root><root>
<a></a>
<b></b></root>
[jaypal:~/Temp] awk '/^<\/root>$/{next}/<\/root>/{sub(/<\/root>/,"");print;next}1' tmp
<root>
<a></a>
<b></b>
<root>
<a></a>
<b></b>
<root>
<a></a>
<b></b>
这也应该有用。虽然它会删除所有</root>
而不仅仅是最后一次出现。
sed '/<\/root>/,$s///' filename
答案 3 :(得分:1)
这可能对您有用:
sed '/<\/root>/,/<root>/{/<\/root>/{h;d};H;//{x;p};${x;s/[^\n]*\n//p};d}' file
这假定每个<root>
标记与结束</root>
标记匹配,并且这些标记出现在单独的行上(根据示例)。
说明:
</root>
代码与开场<root>
代码或文件结尾之间的界限。</root>
标记,请将其保存在保留空间(HS)中,然后将其删除并开始新的循环。<root>
标记,请交换到HS并打印出其内容。</root>
标记和文件的最后一行之间,则切换到HS,删除第一行,即结束</root>
标记并打印剩余部分两次通过的替代解决方案:
sed -n '/<\/root>/=' file | sed -n '$s/$/d/p' | sed -f - file
说明:
</root>
代码答案 4 :(得分:0)
使用时间功能查看哪一个是有效的。 sed应该是有效的。
$time command
在我看来,没有比grep更快的东西。尝试使用awk index()来查看它是否更快。