问题
There are lot of questions about replacing multi-newlines to one newline but no one is working for me.
I have a file:
first line
second line MARKER
third line MARKER
other lines
many other lines
I need to replace two newlines (if they exist) after MARKER
to one newline. A result file should be:
first line
second line MARKER
third line MARKER
other lines
many other lines
I tried sed ':a;N;$!ba;s/MARKER\n\n/MARKER\n/g'
Fail.sed
is useful for single line replacements but has problems with newlines. It can't find \n\n
I tried perl -i -p -e 's/MARKER\n\n/MARKER\n/g'
Fail.
This solution looks closer, but it seems that regexp didn't reacts to \n\n
.
Is it possible to replace \n\n
only after MARKER
and not to replace other \n\n
in the file?
I am interested in one-line-solution, not scripts.
回答1:
I think you were on the right track. In a multi-line program, you would load the entire file into a single scalar and run this substitution on it:
s/MARKER\n\n/MARKER\n/g
The trick to getting a one-liner to load a file into a multi-line string is to set $/
in a BEGIN
block. This code will get executed once, before the input is read.
perl -i -pe 'BEGIN{$/=undef} s/MARKER\n\n/MARKER\n/g' input
回答2:
Your Perl solution doesn't work because you are search for lines that contain two newlines. There is no such thing. Here's one solution:
perl -ne'print if !$m || !/^$/; $m = /MARKER$/;' infile > outfile
Or in-place:
perl -i~ -ne'print if !$m || !/^$/; $m = /MARKER$/;' file
If you're ok with loading the entire file into memory, you can use
perl -0777pe's/MARKER\n\n/MARKER\n/g;' infile > outfile
or
perl -0777pe's/MARKER\n\K\n//g;' infile > outfile
As above, you can use -i~
do edit in-place. Remove the ~
if you don't want to make a backup.
回答3:
awk:
kent$ cat a
first line
second line MARKER
third line MARKER
other lines
many other lines
kent$ awk 'BEGIN{RS="\x034"} {gsub(/MARKER\n\n/,"MARKER\n");printf $0}' a
first line
second line MARKER
third line MARKER
other lines
many other lines
回答4:
See sed one liners.
回答5:
awk '
marker { marker = 0; if (/^$/) next }
/MARKER/ { marker = 1 }
{ print }
'
回答6:
This can be done in very simple sed
.
sed '/MARKER$/{n;/./!d}'
回答7:
This might work for you:
sed '/MARKER/,//{//!d}'
Explanation:
Deletes all lines between MARKER
's preserving the MARKER
lines.
Or:
sed '/MARKER/{n;N;//D}'
Explanation:
Read the next line after MARKER
, then append the line after that. Delete the previous line if the current line is a MARKER
line.
来源:https://stackoverflow.com/questions/7535587/replace-two-newlines-to-one-in-shell-command-line