24

I need to edit several lines in a file such that if a line begins with (av or avpgw) then replace these with new text, else just insert the new text in beginning.

How can I do this using sed ?

Oded
  • 489,969
  • 99
  • 883
  • 1,009
user1765709
  • 441
  • 1
  • 4
  • 8

3 Answers3

21

You can do it this way:

sed -e 's/^avpgw/new text/' -e t -e 's/^av/new text/' -e t -e 's/^/new text/' file

This replaces the pattern with new text (s///) and jumps to the end (t). Otherwise it tries the next pattern. See also sed commands summary.

You can also separate the commands with ;:

sed 's/^avpgw/new text/; t; s/^av/new text/; t; s/^/new text/' file

or put the commands in a sed command file:

s/^avpgw/new text/
t
s/^av/new text/
t
s/^/new text/

and call it this way:

sed -f commandfile file

If you want to ignore case, append an i at the end of the substitute command as in s/^av/new text/i. Another way is to spell it out with character sets s/^[aA][vV]/new text/. But that is not sed specific, for this you can search for regular expressions in general.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
1

This might work for you (GNU sed):

sed -r 's/^av(pgw)?.*/replacement/;t;s/^/replacement /' file
potong
  • 55,640
  • 6
  • 51
  • 83
  • @JanitoVaqueiroFerreiraFilho good point. GNU sed also provides the optional metacharacter `?` which means the same 0 or 1. But if there is no chance of the string `avpgwpgw` `*` is fine. – potong Oct 22 '12 at 17:48
  • Thanks! I guess it all depends on how much we can trust the input =) – Janito Vaqueiro Ferreira Filho Oct 22 '12 at 17:52
  • Thanks. I just wanted to replace the prefix part(avpgw etc.)and not the whole text. It worked perfectly fine, after a minor modification. Is there a way to make it case insensitive. I mean Av,AV,av etc. should all be replaced. – user1765709 Oct 23 '12 at 08:22
0

My answer is but a minor clarification to Olaf's excellent solution above.

If you are using OSX (which for me, using Catalina, uses a 2005 non-GNU version of sed), and you try to use his more-concise semicolon-based solution (repeated below, tiny modification with the 1/2/3's at the end):

sed 's/^avpgw/new text 1/; t; s/^av/new text 2/; t; s/^/new text 3/' file

... you may get an error similar to the below, due to the use of the t command in combination with the semicolons [;] (which are themselves separated from the rest of the command by regular spaces):

sed: 1: "s/^avpgw/new text 1/; t ...": undefined label '; s/^av/new text 2/; t; s/^/new text 3/'

This problem, and a solution, is described in: sed “undefined label” on MacOS

Below is a version of Olaf's "all-in-one command" solution that works on OSX. It's debatable whether the \n characters are really any better than just using extra -es. lolz aside: I'm mainly posting because I wanted to share the "root cause" of this problem so that people using OS X won't drive themselves crazy thinking that their sed version doesn't properly support the t command robustly -- it's just an issue of semicolons versus newlines, that's all!

Test file:

bash-3.2$ cat file
+ cat file
something
avpgw something else
av another thing
text

Original command, executed on OS X:

bash-3.2$ sed 's/^avpgw/new text 1/; t; s/^av/new text 2/; t; s/^/new text 3/' file

sed: 1: "s/^avpgw/new text 1/; t ...": undefined label '; s/^av/new text 2/; t; s/^/new text 3/'

With newlines instead of semicolons:

bash-3.2$ sed $'s/^avpgw/new text 1/\nt\ns/^av/new text 2/\nt\ns/^/new text 3/' file

new text 3something
new text 1 something else
new text 2 another thing
new text 3text
Sean
  • 393
  • 2
  • 11