I've seen a lot of examples regarding this problem, but have yet to see the one that is tailored for my use. Although I'm very familiar with sed I'm ashamed to say that I'm a noob when it comes to more advanced features. Here's the problem at hand.
I have a multi-line pattern that I can successfully match with sed like so,
sed -e '/Favorite Animals/, /!/p
Favorite Animals
Monkey
Penguin
Cat
!
Favorite Things
Shoe
Dog
Wheel
Moth
!
and what I personally like about this expression is that I can match a variable number of lines up to the exclamation character. Now let's say I wanted to do a search and replace on that same pattern. Basically I would like to replace that multi-line pattern that was previously demonstrated with any string of my choosing. Any Ideas? I'm hoping for similar syntax to my demonstrated sed command, but beggars can't be choosers.
The idea is so that I can replace one of the groups delimited by the exclamation with a string. I'll call them "entries". I want to be able to update or overwrite these entries. If I had a new updated version of favorite animals I would like to be able to replace the old entry with a new one like this.
Favorite Animals
Sloth
Platypus
Badger
Dog
!
Favorite Things
Shoe
Dog
Wheel
Moth
!
As you can see I'm no longer a fan of monkeys now.
`sed` command is one of the ways to do replacement task. This command can be used to replace text in a string or a file by using a different pattern.
Basic text substitution using 'sed'Any particular part of a text can be searched and replaced by using searching and replacing pattern by using `sed` command. In the following example, 's' indicates the search and replace task.
There are a variety of options — the i
, c
, and a
commands can all be used.
This amended answer deals with the modified data file now in the question. Here's a mildly augmented version of the modified data
file:
There's material at the start of the file then the key information:
Favourite Animals
Monkey
Penguin
Cat
!
Favourite Things
Shoe
Wheel
Moth
!
and some material at the end of the file too.
All three of these sed
scripts produce the same output:
sed '/Favourite Animals/,/!/c\
Favourite Animals\
Sloth\
Platypus\
Badger\
!
' data
sed '/Favourite Animals/i\
Favourite Animals\
Sloth\
Platypus\
Badger\
!
/Favourite Animals/,/!/d' data
sed '/Favourite Animals/a\
Favourite Animals\
Sloth\
Platypus\
Badger\
!
/Favourite Animals/,/!/d' data
Sample output:
There's material at the start of the file then the key information:
Favourite Animals
Sloth
Platypus
Badger
!
Favourite Things
Shoe
Wheel
Moth
!
and some material at the end of the file too.
It is crucial that the scripts all use the unique string, /Favourite Animals/
and do not key off the repeated trailing context /!/
. If the i
or a
use /!/
instead of /Favourite Animals/
, the outputs change — and not for the better.
/!/i
:
There's material at the start of the file then the key information:
Favourite Animals
Sloth
Platypus
Badger
!
Favorite Things
Shoe
Wheel
Moth
Favourite Animals
Sloth
Platypus
Badger
!
!
and some material at the end of the file too.
/!/a
:
There's material at the start of the file then the key information:
Favourite Animals
Sloth
Platypus
Badger
!
Favorite Things
Shoe
Wheel
Moth
!
Favourite Animals
Sloth
Platypus
Badger
!
and some material at the end of the file too.
Would it be possible to select a range within a range using sed? Basically, what if I wanted to change or remove one/many of my favorite animals within the previously specified range. That is
/Favorite Animals/,/!/...
change something within this range.
Yes, of course. For a single mapping:
sed '/Favourite Animals/,/!/ s/Monkey/Gorilla/'
For multiple mappings:
sed '/Favourite Animals/,/!/ {
s/Monkey/Gorilla/
s/Penguin/Zebra/
s/Cat/Dog/
}'
You can also combine those onto a single line if you wish — use semicolons to separate them:
sed '/Favourite Animals/,/!/ { s/Monkey/Gorilla/; s/Penguin/Zebra/; s/Cat/Dog/; }'
Be aware that GNU sed
and BSD (Mac OS X) sed
have different views on the necessity for the last semicolon — what's shown works with both.
The original answer works with a simpler input file.
Consider the file data
containing:
There's material
at the start of the file
then the key information:
Favourite Animals
Monkey
Penguin
Cat
!
and material at the end of the file too.
Using c
, you might write:
$ sed '/Favourite Animals/,/!/c\
> Replacement material\
> for the favourite animals
> ' data
There's material
at the start of the file
then the key information:
Replacement material
for the favourite animals
and material at the end of the file too.
$
Using i
, you would use:
$ sed '/Favourite Animals/i\
> Replacement material\
> for the favourite animals
> /Favourite Animals/,/!/d' data
There's material
at the start of the file
then the key information:
Replacement material
for the favourite animals
and material at the end of the file too.
$
Using a
, you might write:
$ sed '/!/a\
> Replacement material\
> for the favourite animals
> /Favourite Animals/,/!/d' data
There's material
at the start of the file
then the key information:
Replacement material
for the favourite animals
and material at the end of the file too.
$
Note that with:
c
— you change the whole rangei
— you insert before the first pattern in the range before you delete the entire rangea
— you append after the last pattern in the range before you delete the entire rangeThough, come to think of it, you could insert before the last pattern in the range before deleting the entire range, or append after the first pattern in the range before deleting the entire range. So, the key with i
and a
is to put the 'replacement text' operation before the range-based delete. But c
is most succinct.
The i
(insert) command has ugly syntax, but it works:
sed '/Favorite Animals/i\
some new text\
some more new text\
and a little more
/Favorite Animals/,/!/d'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With