2

I am doing a find and replace with sed, replacing the BASH variable $a (when at the start of a new line) with the BASH variable $b:

sed -i "s#^$a#$b#" ./file.txt

This replaces all matches for ^$a. How can I replace only the first occurrence of ^a within the entire file?

Village
  • 22,513
  • 46
  • 122
  • 163

3 Answers3

6

One way using sed:

sed "s/^$var1/$var2/ ; ta ; b ; :a ; N ; ba" infile

Explanation:

s/^$var1/$var2/             # Do substitution.
ta                          # If substitution succeed, go to label `:a`
b                           # Substitution failed. I still haven't found first line to 
                            # change, so read next line and try again.
:a                          # Label 'a'
N                           # At this position, the substitution has been made, so begin loop
                            # where I will read every line and print until end of file.
ba                          # Go to label 'a' and repeat the loop until end of file.

A test with same example provided by Jaypal:

Content of infile:

ab aa
ab ff
baba aa
ab fff

Run the command:

sed "s/^$var1/$var2/ ; ta ; b ; :a ; N ; ba" infile

And result:

bb aa
ab ff
baba aa
ab fff
Birei
  • 35,723
  • 2
  • 77
  • 82
4

This should work:

sed -i "0,/^\$a/s//\$b/" ./file.txt

You can read more about this at http://www.grymoire.com/Unix/Sed.html#toc-uh-29

Bruno Silva
  • 3,077
  • 18
  • 20
  • 1
    When I try this, I get "sed: -e expression #1, char 3: unexpected `,'". – Village Feb 05 '12 at 03:12
  • Yes, I use "$" instead of "/" because some of the items to be replaced contain "/", but do not contain any "#". – Village Feb 05 '12 at 11:15
  • 1
    I think you shouldn't escape `$` between double quotes in a `sed` script to use `bash` variables inside it. – Birei Feb 05 '12 at 12:20
  • 1
    If your items contain `/` you can escape it with `\/`. – Bruno Silva Feb 05 '12 at 16:53
  • 4
    @Village: You will need to escape the first `#`. Try this: `sed -i "0,\#^$a#s##$b#" ./file.txt`. I removed the escapes before the dollar signs so the variable values will be substituted. Note that the address form `0,addr2` is specific to GNU `sed` (which you are using). – Dennis Williamson Feb 05 '12 at 18:13
1

This might work for you:

 sed -i 'x;/^./{x;b};x;/^'"$a"'/{s//'"$b"'/;h}' file

Or:

 sed -i ':a;$!{N;ba};s/^'"$a/$b"'/m' file
potong
  • 55,640
  • 6
  • 51
  • 83