在Linux中搜索并替换大型单行文件(~2GB)文件

时间:2016-02-20 20:52:01

标签: linux replace sed large-files

我有一个大约2GB的大型XML文件。为了使事情变得有趣,整个数据都在一行中。

我正在尝试在此文件中的特定标记的末尾插入换行符,以使其成为多行文件,这样我就可以将其拆分并对其执行更多操作。

root@server:~# sed -i -e 's/\<\/Dummy\>/\<\/Dummy\>\\\n/g' file_name

我尝试过sed,vi和joe没有运气。 XML中每个节点的长度不同,因此我无法根据字符数拆分文件。

我有办法通过命令行将这个大的单行文件变成多行文件吗?

4 个答案:

答案 0 :(得分:1)

您可以做的是使用xmllint xmllint --format pathtofile.xml将其格式化为规范xml,然后将其格式化为sed。

答案 1 :(得分:0)

我想我实际上是用gawk而不是sed来做这件事。

你没有包含输入数据,所以我会做一些。

$ printf '<a><b></b><b></b></a><a><c></c></a>' | gawk -vRS='</a>' '{print $0 RS}'
<a><b></b><b></b></a>
<a><c></c></a>

通常,awk(或gawk)会将每一行视为唯一记录,每行分为由空格分隔的字段。

如果您通过某个XML标记拆分记录,则可以依赖于print在打印每个“输入记录”后将新行添加为默认ORS(输出记录分隔符)这一事实。

与sed解决方案不同,它会尝试将一个完整的“记录”(行)读入内存以便对其执行操作,我怀疑此解决方案只会使用足够的内存来“记住”空间来逐步执行文件记录分隔符之间。 (这解决了“大文件”问题。)

另外三件事要注意。

首先,记录分隔符不是XML原生的概念,因此任何使用sed,awk或任何本身不能解释XML 的解决方案都是黑客。使用本机支持您的数据格式的工具,您将始终获得更好的结果。

第二,因为在我的例子中,我已经指定了一个记录分隔符,即XML标记的关闭,输入数据可能有三个记录,其中第三个是null。如果在最终的“记录分隔符”后面有换行符,则第三条记录可能会在输出中的另一个RS中终止。被警告。这是事物#1的结果。

第三,这是一个 gawk 解决方案,而不是 awk 解决方案,因为其他awk实现通常不支持多个字符作为记录分隔符。

YMMV。这不是一个很好的解决方案,但它可能足以满足您的需求。

答案 2 :(得分:0)

我公然窃取了ghoti answer {/ 3}}的输入内容:

$ cat file_name
<a><b></b><b></b></a><a><c></c></a>

您的尝试有一些问题,修改为较短的标记:

sed -i -e 's/\<\/a\>/\<\/a\>\\\n/g' file_name
  • 在这种情况下无需-e

    sed -i 's/\<\/a\>/\<\/a\>\\\n/g' file_name
    
  • 为避免必须转义/,我们可以使用不同的分隔符:

    sed -i -e 's|\</a\>|\</a\>\\\n|g' file_name
    
  • 如果您使用< >转义\< \>,则sed 1 认为您的意思是&#34;字边界&#34;,但在这种情况下,您的意思是文字< >并且不应该逃避它们:

    sed -i -e 's|</a>|</a>\\\n|g' file_name
    

    这已经某事

    $ sed -i -e 's|</a>|</a>\\\n|g' file_name
    <a><b></b><b></b></a>\
    <a><c></c></a>\
    [empty line here]
    

因此,如果你真的想在每一行的末尾都有\,那么我们几乎就在那里。 (如果没有,您只需将\\\n替换为\n。)

  • 化妆品:无需写出我们在替换中匹配的所有内容,我们只能使用&

    sed -i -e 's|</a>|&\\\n|g' file_name
    
  • 最后,如果我们的文件恰好以<a>结尾(示例输入有),我们可能希望从输出的末尾删除反斜杠(和换行符!): p>

    $ sed -e 's|</a>|&\\\n|g;s/\\\n$//' file_name
    <a><b></b><b></b></a>\
    <a><c></c></a>
    

当然,所有关于使用非XML工具操纵XML的说法仍然适用:你不应该这样做,如果你这样做,期望你的解决方案容易破解。

1 至少GNU sed会这样做,但这被标记为&#34; Linux&#34;我假设你使用的是GNU sed。

答案 3 :(得分:0)

尝试流选项:

xmllint --stream --format file_name > lintout.xml