sed delete all lines between two lines that contain a string - sed

I have a text file with thousand of lines. I want to delete all lines between the line that starts with XXX and the line that starts with YYY, example
1
2
3
XXX
a
b
c
YYY
x
z
y
should be:
1
2
3
x
z
y
Is that possible with sed or similar?

This might work for you (GNU sed):
sed '/^XXX/{:a;N;/^YYY/Md;ba}' file
This will delete lines between a line beginning XXX and a line beginning YYY. As will:
sed '/^XXX/,/^YYY/d' file
However if the beginning YYYis not matched, the first solution will not remove any lines at all, whereas the second solution will remove all lines from the initial match of XXX to the end of the file.
A slightly different solution for removing lines between lines containing XXX and YYY is:
sed '/XXX/{:a;N;/\n.*YYY/d;ba}' file
The second regexp ensures that YYY does not appear on the first line of the match.

The following works for me:
sed '/XXX/,/YYY/d'

Related

Delete a paragraph from a file using sed

I have a markdown file that looks something like this:
markdown.md
# Title1
line 1
line 2
line 3
# Title2
line 1
line 2
line 3
I'd like to be able to delete one of the paragraphs by searching for the title. I would need to delete the title, the following line, and then every subsequent line that is not blank.
The desired output would be:
# Title2
line 1
line 2
line 3
I was doing some reading about using {} to group multiple commands together but I can't seem to quite get the syntax right.
cat markdown.md | sed '/^# Title1.*/,+1d {/^\s*$/d}'
My thinking was this would delete the line beginning with '# Title1', then the following line with ,+1d, then subsequent lines until a blank line, but i see the following error:
sed: 1: "/^# Title1.*/,+1d { ...": extra characters at the end of d command
I've tried a few variations but no luck. Any help would be appreciated!
This is the kind of sed puzzle that makes me wish for a slightly different tool.
sed -n -e '/Title1/!{p;d;};n;' -e ':a' -e 'n;/./ba'
Loosely translated: "Don't print anything. If it doesn't contain 'Title1', then all right, print it, then start over with the next line. But if it does contain 'Title1', then grab the next line (which will be blank), enter a loop, and keep grabbing new lines until you come to the next empty line."
Using GNU sed
$ sed -z 's/# Title1[^#]*//' input_file
# Title2
line 1
line 2
line 3
This might work for you (GNU sed):
sed '/^# /h;G;/\n# Title1/!P;d' file
If a line begins # , make a copy.
Append the copy to each line and if that line does not contain \n# Title1, print it.
Delete all lines.
Alternative:
sed '/^# Title1/{:a;N;/\n#/!s/\n//;ta;D}' file

Remove line and the one before that matches pattern using sed

I have a file containing the following text:
>seq 1
GAA--ACGAA
>seq 2
CATCTCGGGA
>seq 3
GACG-CG-AG
>seq 4
ATTCCGTGCC
How can I delete the lines containing "-" and the ones before it using sed?
Expected output:
>seq 2
CATCTCGGGA
>seq 4
ATTCCGTGCC
I have tried sed -e '/-/-1d' file, but I get sed: -e expression #1, char 4: unknown command: `-'
Thank you in advance.
Using sed
$ sed 'N;/-/d' input_file
>seq 2
CATCTCGGGA
>seq 4
ATTCCGTGCC
This might work for you (GNU sed):
sed -n 'N;/\n.*-/!{P;D};:a;s/.*//;N;/\n.*-/ba;D' file
Open a two line window and if the second line does not contains - print/delete the first line and repeat.
Otherwise, empty the pattern space and append another line and if the second line does contain - repeat this part again.
Otherwise, delete the first line and repeat.
N.B. This deletes the previous line and any multiples of lines containing -. Also the D deletes upto and including the first newline in the pattern space and the sed cycle omits the automatic reading of the next line into the pattern space if the pattern space is not empty.

sed Remove lines between two patterns (excluding end pattern)

given text like
_adsp TXT "dkim=all"
VVKMU6SE3C2MF88BG4DJQAECMR9SIIF0 NSEC3 1 1 10 C4F407437E8EA4C5 (
175MCHR31K25LP89OVJI5LCE0JA2N2AP
A MX TXT AAAA RRSIG SPF )
RRSIG NSEC3 7 3 1800 (
20200429171433 20200330161758 11672 example.com
H3l26qmtkuiFZCeSYCCAo5krFE3gjM0I8UeQ9jhj3STy
X6fM0YizCHEuv4VZynOJGJc1XJnHRHI+p7yLlZ+OVseK
UfIkPVP+VOmlerwozEpM+Tnt8evwnMTDbcn0zxf/6YJx
kZeO2AszWkRZ0bctqW7INYo8YuyyuTSxSr8se27fiaPA
4GXQymepGgv/JGqargzHbyhhkDhENmNo7Qwkjl+a0kI4
6qqKcEWCsDvnlYUQiDFzc5oRs2j7TT9uybTfwUDQxV+t
MQFMhzu7LNbRIUuOb16sAEGSdl9mWQ4sZRJ9wuXJWbso
G+3tY0pBbq4ffScz/JKcrJ0qAuBF1F5JcQ== )
$TTL 1800
I want to get rid by the part with the "(not beginning with whitespace) NSEC3 " until the first line not beginning with a whitespace character.
resulting
_adsp TXT "dkim=all"
$TTL 1800
in the example.
I tried sed '/^[^\s].*\sNSEC3\s/,/^[^\s]/d;' filename but that doesn't work as expected, example results in
_adsp TXT "dkim=all"
H3l26qmtkuiFZCeSYCCAo5krFE3gjM0I8UeQ9jhj3STy
X6fM0YizCHEuv4VZynOJGJc1XJnHRHI+p7yLlZ+OVseK
UfIkPVP+VOmlerwozEpM+Tnt8evwnMTDbcn0zxf/6YJx
kZeO2AszWkRZ0bctqW7INYo8YuyyuTSxSr8se27fiaPA
4GXQymepGgv/JGqargzHbyhhkDhENmNo7Qwkjl+a0kI4
6qqKcEWCsDvnlYUQiDFzc5oRs2j7TT9uybTfwUDQxV+t
MQFMhzu7LNbRIUuOb16sAEGSdl9mWQ4sZRJ9wuXJWbso
G+3tY0pBbq4ffScz/JKcrJ0qAuBF1F5JcQ== )
$TTL 1800
so resuming printout way too early?
what do I miss?
thank you
P.S.:
you maybe see what I want to do is removing DNSSEC parts out of an named zone. didn't find any other way to remove RRSIG and NSEC3 entries, yet. If someone has an idea, I would appreciate that too.
[\s] matches a literal \ or s characters. It doesn't match whitespace.
The /^[^\s]/d; (if [\s] would work as you expect) will also include removing the last line with non-leading whitespaces. I think you have to loop manually.
On the example you've given, the following seems to work:
sed -n '/^[^ \t].*\sNSEC3\s/{ :a; n; /^[^ \t]/bb; ba}; :b; p'
This might work for you (GNU sed):
sed -n '/^\S.*NSEC/{:a;n;/^\S/!ba};p' file
Turn off implicit printing by using the -n option.
Throw away lines between one starting with a non-space and containing the string NSEC and any lines not starting with a non-space.
Print all other lines.
Alternative:
sed '/^\S.*NSEC/,/^\S/{/^\S.*NSEC\|^\s/d}' file
Yet another alternative:
sed '/^\S.*NSEC/{:a;N;/\n\S/!ba;s/.*\n//}' file
And another:
sed '/^\S.*NSEC/{:a;N;/\n\S/!s/\n//;ta;D}' file
N.B. The first two solutions will delete lines regardless of a line delimiting the end of the deletions. Whereas the last two solutions will only delete lines if there is a line delimiting the end of the deletions.

sed delete block of lines after pattern1 to pattern2, but not the line matching pattern1 itself?

I am struggling to use sed to work through 'testfile.txt' and every time it encounters a line that starts delete_me: abc it will then:
leave the line delete_me: abc intact
but delete all the lines that follow until the next blank line is reached in the file.
eg. I want this input:
delete_me: abc
sSAsaAaSA
AsaSAsaSAsa
asASAsS
^--- <blank line>
...to be changed to just this one line:
delete_me: abc
I have tried:
sed '/delete_me/ {n;d}' jil_testfile.txt
# deletes only the first line after 'delete_me'
sed '/delete_me/,/^$/d' jil_testfile.txt
# nearly works but deletes the 'delete_me' line too which I want to stay preserved.
Any suggestions please?
This might work for you (GNU sed):
sed -n ':a;/delete_me/{p;:b;n;//ba;bb};p' file
Print lines as normal until the first occurrence of delete_me. Print this line and do not print any further lines unless that line contains delete_me.
As the spec has changed since I wrote the first solution, here is new one:
sed -n '/delete_me/{p;:a;n;/^$/b;ba};p' file

In a sed transformation, how to apply a slightly different pattern just for the last line?

How can I turn this:
aaa
bbb
ccc
into this:
aaa,
bbb,
ccc
using sed?
Note how all lines end a comma, except the last one.
In my real problem I also do some regex substitutions on the lines. Is there a solution that doesn't duplicate them?
You could use:
sed '$q;s/$/,/'
If you want to apply a different substitution on the last line, you can still use the $ address:
sed '$s/$/;/;$q;s/$/,/'
The above will replace the end of the line with ; if it's the last line, otherwise it will use ,.
$s/$/;/ = at the last line, replace the end of the line with ;
$q = at the last line, quit
s/$/,/ = replace the end of the line with ,
The last s command will run for each line, but not for the last line in which the q command at 2. tells it to quit.
See:
Restricting to a line number
Ranges by line number
The q or quit command