'Replace same occurrence of word with different words using sed
I want to replace 2 same words in file(app.properties) with 2 different words using sed command. Example:
mysql.host=<<CHANGE_ME>>
mysql.username=testuser
mysql.port=3306
mysql.db.password=<<CHANGE_ME>>
required output will be
mysql.host=localhost
mysql.username=testuser
mysql.port=3306
mysql.db.password=password123
I tried below command:
sed -e "s/<<CHANGE_ME>>/localhost/1" -e "s/<<CHANGE_ME>>/password123/2" app.properties > /home/centos/SCRIPT/io.properties_new
However I am getting localhost at both the places.
Solution 1:[1]
I'm sure it's not impossible, but also that you will not be able to figure out how it works once you find an answer. A better solution is to switch to a language which is more human-readable, so you can understand what it does.
awk 'BEGIN { split("localhost:password123", items, ":") }
    /<<CHANGE_ME>>/ { sub(/<<CHANGE_ME>>/, items[++i]) } 1' input_file >output_file
The BEGIN block creates an array items of replacements. The main script then increments i every time we perform a replacement, indexing further into items for the replacement string.
Solution 2:[2]
This may be possible but I don't know if this is really readable for everyone. Something like this might suite you :
sed -e '0,/<<CHANGE_ME>>/{s/<<CHANGE_ME>>/localhost/}' -e '1,/<<CHANGE_ME>>/{s/<<CHANGE_ME>>/password123/}' app.properties > /home/centos/SCRIPT/io.properties_new
If you have any idea to improve this, don't hesitate. I would really like to learn the best way to do this too :D
Solution 3:[3]
Using sed
$ sed '/host/s/\(=\).*/\1localhost/;/password/s/\(=\).*/\1password123/' input_file
mysql.host=localhost
mysql.username=testuser
mysql.port=3306
mysql.db.password=password123
    					Solution 4:[4]
With sed, using a wonderfully confusing if (first time) do x, else do y logic:
sed '/<CHANGE_ME>/{bb;:a;s/<CHANGE_ME>/password123/;:b;x;s/E//;x;ta;s/<CHANGE_ME>/localhost/;x;s/^/E/;x}' input_file
Writing each command of the sed script on its own line makes it more understandable, or at least easier for me to expain it:
/<CHANGE_ME>/{
  bb
  :a
  s/<CHANGE_ME>/password123/
  :b
  x
  s/E//
  x
  ta
  s/<CHANGE_ME>/localhost/
  x
  s/^/E/
  x
}
Here's the explanation:
/<CHANGE_ME>/{…}means that the stuff in{…}is only applied to lines matching<CHANGE_ME>;
bb: "branch to (go to):b", in this case used to skip the first substitution command;:a: a target for anotherbranch ortest-and-branch command;s/…/…/: you know what it does, but we skip this the first time the script is run;b: branches to the end of the script, skipping everything (because we are giving no argument tob);:b: the target of the commandbbat 1.;x: swap patter space (the line you're dealing with at the moment), with the hold space (a kind of variable that you can put stuff into viax,h, andHcommands);s/E//: tries to match and delete aE(just because that's the initial of my name), which fails the first time we run this, because the hold space that we've swapped earlier with the patter space was empty;x: undos what the previousxdid, so we're back on working with the line matching<CHANGE_ME>;ta: tests if last peformeds/…/…/command succeeded and, if so, it goes to:a, otherwise it's a no-op; the first time we run the script this is a no-op, because step 6 failed;s/…/…/: you know what it does;x: see aboves/^/E/: inserts theEat the beginning of the line, so that next time we run the script substitution of step 7 succeedes, step 9 successfully branches to:a, step 3 is peformed for the first time, and step 4 exits the script for ever;x: see above
Solution 5:[5]
Perhaps this might help:
sed -e '1s/<<CHANGE_ME>>/localhost/' \
    -e '4s/<<CHANGE_ME>>/password123/' \
      app.properties > /home/centos/SCRIPT/io.properties_new
    					Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | tripleee | 
| Solution 2 | Kayneth | 
| Solution 3 | HatLess | 
| Solution 4 | |
| Solution 5 | tripleee | 
