'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
: "b
ranch to (go to):b
", in this case used to skip the first substitution command;:a
: a target for anotherb
ranch ort
est-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 commandbb
at 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
, andH
commands);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 previousx
did, 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 theE
at 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 |