我有一些由程序生成的文件,该程序没有在记录末尾添加换行符。我想在记录之间添加换行符,我可以使用简单的 sed 脚本来完成此操作:
sed -e 's/}{/}\n{/g'
问题在于输入文件的大小为多个 GB,因此 sed 的输入行的长度为多个 GB。 sed 尝试在内存中保存一行,但在这种情况下不起作用。我尝试了该--unbuffered
选项,但这似乎使它变慢并且不允许它正确完成。
答案1
您可以使用另一个工具来设置输入记录分隔符。例如
Perl
perl -pe 'BEGIN{ $/="}{" } s/}{/}\n{/g' file
特殊变量
$/
是输入记录分隔符。将其设置为}{
将行定义为以 结尾}{
。这样你就可以实现你想要的,而无需将整个内容读入内存。莫克或呆呆
awk -v RS="}{" -vORS= 'NR > 1 {print "}\n{"}; {print}' file
这是同样的想法。
RS="}{"
将记录分隔符设置为}{
,然后打印}
、换行符{
(第一条记录除外)和当前记录。
答案2
Perl 来拯救:
perl -i~ -e ' $/ = \1024;
while (<>) {
print "\n" if $closing and /^{/;
undef $closing;
s/}{/}\n{/g;
print;
$closing = 1 if /}$/;
} ' input1 input2
设置$/
为\1024
将以 1024 字节为单位读取文件。该$closing
变量处理一个块以 结尾}
而下一个块以 开头的情况{
。
答案3
你应该做:
{ <infile tr \} \\n;echo {; } | paste -d'}\n' - /dev/null >outfile
这可能是最有效的解决方案。
这可以{}
保护任何可能的跟踪数据。通过另一个tr
过程,您可以交换它并在第一个字段的头部添加一个空行{
。喜欢...
tr {} '}\n'| paste -d{\\0 /dev/null - | tr {}\\n \\n{}
所以第一个,使用 don 的示例数据,会:
printf '{one}{two}{three}{four}' |
{ tr \} \\n; echo {; } |
paste -d'}\n' - /dev/null
{one}
{two}
{three}
{four}
{}
……第二个也是……
printf '{one}{two}{three}{four}' |
tr {} '}\n'| paste -d{\\0 /dev/null - |
tr {}\\n \\n{}
#leading blank
{one}
{two}
{three}
{four}
第二个示例没有尾随换行符 - 尽管第一个示例有一个。
答案4
一个sed
类似于二进制的实用程序称为bbe
我发现在这种情况下使用类似 sed 的语法是最简单的。
我很多更喜欢使用该bbe
实用程序(可通过您的 {uni,linu}x 的软件包安装 eq 获得apt-get
)。或者这里如果您是 git 人群中的一员,尽管我还没有亲自审查过该特定链接。
1. 支持s/before/after/
习语
它是一个“二进制块编辑器”,支持类似 sed 的(以及其他)操作。这包括s/before/after/
您需要的超级常见替换习语。请注意,因为从 的角度来看本身没有行bbe
,所以命令末尾没有“global g”。
作为快速测试(注意必需的-e
):
$ echo hello | bbe -e 's/l/(replaced)/'
产生:
he(replaced)(replaced)o
2.在您的具体转换}{
情况下}\n{
因此,如果我们有一个巨大的文件,其中包含一百万个数字,格式为{1}{2}{3}
……{1000000}
没有回车符,我们可以轻松地交换}{
,}\n{
并且每行一个数字。
这将使用以下bbe
命令:
bbe -e 's/}{/}\n{/'
正如在此 zsh 循环中所测试的,我们仅抓取其尾部:
$ for ((num=0; num<1000000; num++)) do; echo -n "{$num}"; done | bbe -e 's/}{/}\n{/' | tail
这会产生这样的结果:
{999990}
{999991}
{999992}
{999993}
{999994}
{999995}
{999996}
{999997}
{999998}
{999999}
(当然没有尾随回车符。)