I'm trying to replace a multiline chunk of text between two known tags, inside a file. This has the following structure:
#STARTTAG
some text with numbers 123
and dots . that I want
to replace .
#ENDTAG
I've been trying different approaches based on what I've seen online including sed, awk, perl, but I can't seem to make it work.
For instance, this is what I've been trying to implement:
sed -i '' 's/STARTTAG.*ENDTAG/alternative text/g' somefile
but it doesn't do anything. I tried adding ' and " to each string (i.e. the tags & replacement text) but it just does nothing. I'm not sure what I'm doing wrong. Note that I would like both the text to be replaced and the alternative texts to be multiline.
Thank you
What I would do:
sed '/STARTTAG/,/ENDTAG/{s/.*/alternative text/g;q}' file
yields:
alternative text
The q
command is to instruct sed
to q
uit.
sed
is a line stream oriented tool, so it's purpose is not to process multilines easily for cases more complicated.
If you need to keep the tags, better use awk
to not have a convoluted and non readable & maintenable sed
command:
awk '
BEGIN{p=1}
$1=="#STARTTAG"{p=0;print;next}
$1=="#ENDTAG"{print "alternative text";p=1}
p
' file
#STARTTAG
alternative text
#ENDTAG
If you need to change the file on the fly, use sponge
from more-utils
(debian):
awk '...' file | sponge file
Another proper approach, is to use perl, then, the regex looks more natural:
perl -g -pe 's/(#STARTTAG).*?(#ENDTAG)/$1\nalternative text\n$2/s' file
-g
require Perl
's >= 5.36
. If you have lower version, use perl -0777
instead.
With this Perl's command, you can use -i
switch like sed
:
perl -i -g '...' file
LESS='+/^ +-g' perldoc perlrun
-g
undefines the input record separator ($/) and thus enables the slurp mode. In other words, it causes Perl to read whole files at once, instead of line by line.