sed替代搜索和替换很长的行


9

我有一个程序生成的文件,该文件未在记录的末尾添加换行符。我想在记录之间添加换行符,我可以使用一个简单的sed脚本来做到这一点:

sed -e 's/}{/}\n{/g'

问题在于输入文件的大小为数GB,因此sed的输入行的长度为数GB。sed尝试在内存中保留一行,在这种情况下不起作用。我尝试了该--unbuffered选项,但这似乎会使它变慢,并且无法正确完成。


是否可以将示例输入文件上传到某个地方,以供我们尝试一些想法?
mkc 2015年

3
也许您可以先tr翻译}\n,然后再在每行末尾sed添加}?像这样:tr '}' '\n' < your_file.txt| sed 's/$/}/'
user43791 2015年

在文件末尾添加换行符是否有帮助?像:printf "\n" >> file
保姆2015年

1
@Ketan,我假设编写一个包含78个垃圾字符的文件,然后}{重复直到它达到几GB长为止。
保姆2015年

@nanny-好点-但是您从哪里获得78?如果记录已被阻止,则dd if=file cbs=80 conv=unblock可以执行此操作-但这很少那么简单。
mikeserv

Answers:


7

您可以使用另一个工具来设置输入记录分隔符。例如

  • 佩尔

    perl -pe 'BEGIN{ $/="}{" } s/}{/}\n{/g' file
    

    特殊变量$/是输入记录分隔符。将其设置为}{定义以结尾的行}{。这样,您就可以实现所需的内容,而无需将整个内容读入内存。

  • 花胶或花胶

    awk -v RS="}{" -vORS= 'NR > 1 {print "}\n{"}; {print}' file 
    

    这是相同的想法。RS="}{"将记录分隔符设置为}{,然后打印},换行符{(第一条记录除外)和当前记录。


3

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可变手柄的情况下当在块的端部}和与下一个的开始{


1
+1,可能是最好的解决方案;其他perl / awk解决方案也可以正常工作,但是如果第一个记录分隔符出现在价值约17GB的字符之后怎么办?
don_crissti

2

你应该做:

{ <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}

第二个示例没有结尾的换行符-尽管第一个示例有一个结尾。


0

类似于Binary 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}

(当然,不带回车符。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.