Replace SED with "dynamic variable" from backreference
UPDATED
Let's say I have a file with this content
database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"
%database_driver%
%database_host%
%database_port%
Now I would like to replace% database *****% with the contents of the corresponding variable, so we end up with
pdo_mysql
11.22.33.44
3306
Now I do it line by line, but I would like a single replace command to replace all values ββat once
I tried this
sed -r "s/%(database.*)%/$\1/g" file.yml
I am trying to create a variable from the second backlink but it doesn't work, it gets this
$database_driver
So I am getting the variable name, not the value
Any ideas?
UPDATE I have a number of answers, but none of them seem to work and they all look very complicated. I would still like an answer to my original question: is there a way to make this work
sed -r "s/%(database.*)%/$\1/g" file.yml
This replaces
%SOMETHING% into $SOMETHING
and
%SOMETHING_ELSE% into $SOMETHING_ELSE.
But I need VALUE $ SOMETHING and $ SOMETHING_ELSE This would be the most ideal solution I guess. Much shorter and more readable suggested solutions
source to share
Everything in sed lol
sed '/^database.*=/{p;s/\(database[^=]*\)/%\1%/;H;d};/^%database/{G;s/^\([^\n]*\).*\1="\([^"]*\).*/\2/}' file
It basically saves the lines you want to retrieve and then replaces the line you want to replace with the stored value.
Will work with shared data as agreed later.
Output
database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"
pdo_mysql
11.22.33.44
3306
As hek2mgl mentioned, you can also put it in a script file
/^database.*=/{p;s/\(database[^=]*\)/%\1%/;H;d}
/^%database/{G;s/^\([^\n]*\).*\1="\([^"]*\).*/\2/}
Running from
sed -f "sedscript" file
source to share
$ sed -f <(sed '/^$/ q; s/\([^=]*\)="\([^"]*\)"/s|%\1%|\2|;/' file) file
File
database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"
%database_driver%
%database_host%
%database_port%
Output
database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"
pdo_mysql
11.22.33.44
3306
Explanation:
sed '/^$/ q; s/\([^=]*\)="\([^"]*\)"/s|%\1%|\2|;/'
Creates a command input for external sed
. It stops at an empty line and until then converts the assignment expressions to expressions such as:
s|%database_driver%|pdo_mysql|;
s|%database_host%|11.22.33.44|;
s|%database_port%|3306|;
This results in "
behaving like '
in bash (no escape sequences or interpolation with those double quotes) and assumes that between% is not a character specific to sed
(you can guarantee that by replacing [^=]
with a range of valid characters such as [_0-9a-zA-Z]
) ...
Note . You might want to write the template in the correct langueage template like ERB or Handlerbars instead.
source to share
I would use Perl. It's much easier in Perl than sed. For example:
perl -pe 's/%([^%]*)%/$vars{$1}/eg; if (/(\w+)="(.*)"/) { $vars{$1} = $2; }' filename
More readable:
s/%(\w+)%/$vars{$1}/eg; # replace %%-encased words with the remembered value
# for the encased word
if (/(\w+)="(.*)"/) { # When finding an assignment
$vars{$1} = $2; # remember the assigned value.
}
This approach will allow you to use variables in variable assignments, i.e. what's the entrance
database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"
database_connstr="mysql:host=%database_host%;port=%database_port%"
%database_driver%
%database_host%
%database_port%
%database_connstr%
produces
database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"
database_connstr="mysql:host=11.22.33.44;port=3306"
pdo_mysql
11.22.33.44
3306
mysql:host=11.22.33.44;port=3306
source to share
This command sed
will execute:
sed -nr 's#database_([^"]*)="([^"]*)"#s/(\1:\\s*)%[^%]*%/\\1\2/#p' file| sed -r -f- file
Explanation:
sed -nr 's#database_([^"]*)="([^"]*)"#s/(\1:\\s*)%[^%]*%/\\1\2/#p' file
generates output:
s/(driver:\s*)%[^%]*%/\1pdo_mysql/
s/(host:\s*)%[^%]*%/\111.22.33.44/
s/(port:\s*)%[^%]*%/\13306/
which is then used as a sed
script for the next one sed
after the channel.
UPDATE:
For your new file, this will be:
sed -nr 's#database_([^"]*)="([^"]*)"#s/%[^%]*\1%/\2/#p' file | sed -r -f- file
source to share