Reputation: 16512
I have a file that, occasionally, has split lines. The split is signaled by the fact that the line starts with '+' (possibly preceeded by spaces).
line 1
line 2
+ continue 2
line 3
...
I'd like join the split line back:
line 1
line 2 continue 2
line 3
...
using sed. I'm not clear how to join a line with the preceeding one.
Any suggestion?
Upvotes: 22
Views: 12119
Reputation: 58371
This might work for you:
sed 'N;s/\n\s*+//;P;D' file
These are actually four commands:
N
s/\n\s*+//
P
D
The relevant manual page parts are
To add 1 or more +
lines, use:
sed ':a;N;s/\n\s*+//;ta;P;D' file
Upvotes: 29
Reputation: 5655
Different use of hold space with POSIX sed... to load the entire file into the hold space before merging lines.
sed -n '1x;1!H;${g;s/\n\s*+//g;p}'
1x
on the first line, swap the line into the empty hold space1!H
on non-first lines, append to the hold space$
on the last line:
g
get the hold space (the entire file)s/\n\s*+//g
replace newlines preceeding +
p
print everythingInput:
line 1
line 2
+ continue 2
+ continue 2 even more
line 3
+ continued
becomes
line 1
line 2 continue 2 continue 2 even more
line 3 continued
This (or potong's answer) might be more interesting than a sed -z
implementation if other commands were desired for other manipulations of the data you can simply stick them in before 1!H
, while sed -z
is immediately loading the entire file into the pattern space. That means you aren't manipulating single lines at any point. Same for perl -0777
.
In other words, if you want to also eliminate comment lines starting with *
, add in /^\s*\*/d
to delete the line
sed -n '1x;
/^\s*\*/d;
1!H;${g;s/\n\s*+//g;p}'
versus:
sed -z 's/\n\s*+//g;
s/\n\s*\*[^\n]*\n/\n/g'
The former's accumulation in the hold space line by line keeps you in classic sed line processing land, while the latter's sed -z
dumps you into what could be some painful substring regexes.
But that's sort of an edge case, and you could always just pipe sed -z
back into sed. So +1 for that.
Footnote for internet searches: This is SPICE netlist syntax.
Upvotes: 4
Reputation: 975
A solution for versions of sed
that can read NUL separated data, like here GNU Sed's -z
:
sed -z 's/\n\s*+//g'
Compared to potong's solution this has the advantage of being able to join multiple lines that start with +
. For example:
line 1
line 2
+ continue 2
+ continue 2 even more
line 3
becomes
line 1
line 2 continue 2 continue 2 even more
line 3
Upvotes: 2
Reputation:
You can use Vim in Ex mode:
ex -sc g/+/-j -cx file
g
global search
-
select previous line
j
join with next line
x
save and close
Upvotes: 3
Reputation: 246764
I'm not partial to sed so this was a nice challenge for me.
sed -n '1{h;n};/^ *+ */{s// /;H;n};{x;s/\n//g;p};${x;p}'
In awk this is approximately:
awk '
NR == 1 {hold = $0; next}
/^ *\+/ {$1 = ""; hold=hold $0; next}
{print hold; hold = $0}
END {if (hold) print hold}
'
If the last line is a "+" line, the sed version will print a trailing blank line. Couldn't figure out how to suppress it.
Upvotes: 3
Reputation: 212228
Doing this in sed is certainly a good exercise, but it's pretty trivial in perl:
perl -0777 -pe 's/\n\s*\+//g' input
Upvotes: 4