SED替换为后向引用的“动态变量”构建

时间:2015-07-08 12:29:50

标签: bash sed

已更新

假设我有一个包含此内容的文件

database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"


%database_driver%
%database_host%
%database_port%

现在我想用相应变量的内容替换%database *****%,所以我最终会用

pdo_mysql
11.22.33.44
3306

我现在如何逐行完成此操作,但我希望有一个sed replace命令一次替换所有值

我试过这个

sed -r  "s/%(database.*)%/$\1/g" file.yml

我正在尝试从第二个反向引用创建变量,但这不起作用,它得到了这个

$database_driver

所以我得到变量的名称,而不是值

有什么想法吗?

更新 我有很多答案但是它们似乎都没有用,而且看起来都非常困难。 我仍然想回答我最初的问题:有没有办法让这项工作

sed -r  "s/%(database.*)%/$\1/g" file.yml

这取代了

%SOMETHING%  into $SOMETHING 

%SOMETHING_ELSE%  into $SOMETHING_ELSE.

但我需要$ SOMETHING和$ SOMETHING_ELSE的值 这是我猜的最理想的解决方案。所提出的解决方案更短,更易读

6 个答案:

答案 0 :(得分:1)

我会使用awk,如下所示:

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

在GNU grep的帮助下,你甚至可以使用它:

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

答案 1 :(得分:1)

全部在sed lol

sed '/^database.*=/{p;s/\(database[^=]*\)/%\1%/;H;d};/^%database/{G;s/^\([^\n]*\).*\1="\([^"]*\).*/\2/}' file

基本上它会保存您想要的值,然后将要替换的行替换为它保存的值。

将在以后匹配时使用通用数据。

输出

database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"


pdo_mysql
11.22.33.44
3306

正如hek2mgl所提到的,你也可以把它放在一个脚本文件中

 /^database.*=/{p;s/\(database[^=]*\)/%\1%/;H;d}
 /^%database/{G;s/^\([^\n]*\).*\1="\([^"]*\).*/\2/}

运行
sed -f "sedscript" file

答案 2 :(得分:1)

$ sed -f <(sed  '/^$/ q; s/\([^=]*\)="\([^"]*\)"/s|%\1%|\2|;/' file) file

文件

database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"


%database_driver%
%database_host%
%database_port%

输出

database_driver="pdo_mysql"
database_host="11.22.33.44"
database_port="3306"


pdo_mysql
11.22.33.44
3306

说明:

sed  '/^$/ q; s/\([^=]*\)="\([^"]*\)"/s|%\1%|\2|;/'

为外部sed创建命令输入。它在空行停止,在此之前,将赋值表达式转换为表达式,例如:

s|%database_driver%|pdo_mysql|;
s|%database_host%|11.22.33.44|;
s|%database_port%|3306|;

这使得"在bash中表现得像'一样(没有转义序列或使用这些双引号进行插值),并假设%之间没有任何内容对sed特殊的字符(您可以通过将[^=]替换为一系列允许的字符(例如[_0-9a-zA-Z])来确保这一点。

注意:您可能希望在适当的模板语言中编写模板,例如ERB或Handlerbars,而不是这样做。

答案 3 :(得分:1)

我使用Perl。这在Perl中比在sed中容易得多。例如:

perl -pe 's/%([^%]*)%/$vars{$1}/eg; if (/(\w+)="(.*)"/) { $vars{$1} = $2; }' filename

更可读:

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

这种方法甚至可以让你在变量赋值中使用变量,也就是说输入

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%

产生

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

答案 4 :(得分:1)

这个sed命令将执行:

sed -nr 's#database_([^"]*)="([^"]*)"#s/(\1:\\s*)%[^%]*%/\\1\2/#p' file| sed -r -f- file

说明:

sed -nr 's#database_([^"]*)="([^"]*)"#s/(\1:\\s*)%[^%]*%/\\1\2/#p' file

生成输出:

s/(driver:\s*)%[^%]*%/\1pdo_mysql/
s/(host:\s*)%[^%]*%/\111.22.33.44/
s/(port:\s*)%[^%]*%/\13306/

然后用作管道后下一个sed的{​​{1}}脚本。

更新:

对于您的新文件,它将是:

sed

答案 5 :(得分:0)

Sed用于单个行上的简单替换,这就是全部。只需使用awk:

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