Sed alternative for search and replace on very long lines

You can use another tool that lets you set the input record separator. For example

  • Perl

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

    The special variable $/ is the input record separator. Setting it to }{ defines lines as ending in }{. That way you can achieve what you want without reading the entire thing into memory.

  • mawk or gawk

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

    This is the same idea. RS="}{" sets the record separator to }{ and then you print }, a newline, { (except for the first record) and the current record.


Perl to the rescue:

perl -i~ -e ' $/ = \1024;
              while (<>) {
                  print "\n" if $closing and /^{/;
                  undef $closing;
                  s/}{/}\n{/g;
                  print;
                  $closing = 1 if /}$/;
              } ' input1 input2

Setting $/ to \1024 will read the file in chunks of 1024 bytes. The $closing variable handles the case when a chunk ends in } and the next one starts with {.


You should do:

{ <infile tr \} \\n;echo {; } | paste -d'}\n' - /dev/null >outfile

It's probably the most efficient solution.

That puts a {} to protect any possible trailing data. With one more tr process you can swap that around and do a blank line at the head of the first { field. Like...

tr {} '}\n'| paste -d{\\0 /dev/null - | tr {}\\n \\n{}

So the first, with don's example data, does:

printf '{one}{two}{three}{four}' |
{ tr \} \\n; echo {; }           |
paste -d'}\n' - /dev/null
{one}
{two}
{three}
{four}
{}

...and the second one does...

printf '{one}{two}{three}{four}'      |
tr {} '}\n'| paste -d{\\0 /dev/null - |
tr {}\\n \\n{}
#leading blank
{one}
{two}
{three}
{four}

There is no trailing newline for the second example - though there is one for the first.

Tags:

Sed