7/03/2025

 sed ':start;N;s/\n+ / /;t start;P;D' FileIn > FileOut

: denotes a label and start is an arbitrary name. 

N appends the next line of input into the pattern space. 

Then s tries to replace a newline followed by "+ " with a space; this will only work if the newly appended line starts with +

If s works then t start will jump to :start, so N will append yet another line and so on. 

This way the pattern space accumulates exactly what you need, converting one "<newline>+ " at a time, until there comes a line that doesn't start with "+ " and therefore s finds no match for "\n+ ".

After s finds no match for \n+ , t does not jump, P is executed. 

P prints the pattern space up to the first embedded newline. 

This is exactly the accumulated data from before the latest N that appended the line not beginning with "+ ". 

Next D removes what has just been printed and starts a new cycle without reading a new line of input. 

Not-yet-printed text (i.e. the line not beginning with + ) survives in the pattern space and N can append to it.


Note the code is very simple. 

Previously (in the mediocre solution) we needed a special case for the first line, another for the last line. 

Here N, P, D and the default rules of printing (i.e. the lack of -n) do the job naturally. 

They are perfect for what you want to do.

沒有留言:

張貼留言