Reputation: 43
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.
Upvotes: 0
Views: 282
Reputation: 1
Perhaps this might help:
sed -e '1s/<<CHANGE_ME>>/localhost/' \
-e '4s/<<CHANGE_ME>>/password123/' \
app.properties > /home/centos/SCRIPT/io.properties_new
Upvotes: 0
Reputation: 28416
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 another b
ranch or t
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 to b
);:b
: the target of the command bb
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 via x
, h
, and H
commands);s/E//
: tries to match and delete a E
(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 previous x
did, so we're back on working with the line matching <CHANGE_ME>
;ta
: tests if last peformed s/…/…/
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 the E
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 aboveUpvotes: 0
Reputation: 189397
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.
Upvotes: 2
Reputation: 101
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
Upvotes: 0