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

+3


source to share


6 answers


I would use awk

for example:

awk -F'"| +' '$1=="database_driver="{d=$2}/%database_driver%/{$2=d}1' a.txt

      



With GNU, grep

you can even use this:

driver=$(grep -oP 'driver="\K[^"]+' a.txt)
sed "s/%database_driver%/$driver/" a.txt

      

+1


source


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

      

+1


source


$ 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.

+1


source


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

      

+1


source


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

      

+1


source


Sed for simple substitutions on separate lines, that's all. Just use awk:

$ awk -F'[="%]' 'NF==4{map[$1]=$3;next} NF{print map[$2]}' file
pdo_mysql
11.22.33.44
3306

      

0


source







All Articles