我在设置文件中有以下数据库连接行:
$database = 'mysql://custom_user:custom_password@localhost/custom_database';
我想使用bash脚本更新custom_user,custom_password和custom_database,而bash脚本并不知道它们的值,否则我只会替换它。
如何将该行更新为:
$database = 'mysql://new_user:new_password@localhost/new_database';
使用sed或awk?
编辑:如果答案直接解决了问题,那将会很好。请不要假设输入数据是如何构造的,就好像它没有被处理那样我肯定会将问题的这一部分添加到问题中。Ruslan在评论中的第一个答案是完美的,他的详细答案对我的问题来说太过分了。 Ed的答案也有效,但我接受了Ruslan的回答,因为他是第一个提出工作代码的人。
同样,这个问题根本不是关于如何构建像密码这样的输入数据。
答案 0 :(得分:0)
sed用于单个行上的简单替换,即全部。在这种情况下,你的替换是在一条单独的行上,但它并不简单,因为密码,例如,可以包含任何字符,所以你在sed转义/引用地狱(见Is it possible to escape regex metacharacters reliably with sed)
只需使用awk,因为它理解文字字符串:
$ new='$database = '\''mysql://new_user:new_password@localhost/new_database'\'';' \
awk 'index($0,"$database ="){$0=sprintf("%s",ENVIRON["new"])} 1' file
$database = 'mysql://new_user:new_password@localhost/new_database';
这适用于现有或替换行中的任何字符。当新密码包含&
时,请查看您问题评论中建议的与sed脚本的区别:
$ new='$database = '\''mysql://new_user:foo&bar@localhost/new_database'\'';' \
awk 'index($0,"$database ="){$0=sprintf("%s",ENVIRON["new"])} 1' file
$database = 'mysql://new_user:foo&bar@localhost/new_database';
$ new='$database = '\''mysql://new_user:foo&bar@localhost/new_database'\'';' \
sed -e 's%^\(\s*\$database\s*=\).*;%\1 '"$new"';%' file
$database = 'mysql://new_user:foo$database = 'mysql://custom_user:custom_password@localhost/custom_database';bar@localhost/new_database';
答案 1 :(得分:0)
配置文件中的表达式看起来像PHP代码,而数据库的值很可能是URI。
根据RFC 3986,特殊字符必须在URI部分中进行百分比编码。让我们使用#
字符作为SED替换的分隔符,因为字符必须在任何地方进行百分比编码,但显然不会在URI中使用的片段标记除外。
假设分配不在多行上分配。然后,您可以运行以下命令将旧$database
变量替换为新值:
# If you want to automate escaping, use rawurlencode() function, for example:
user=$(php -r 'echo rawurlencode($argv[1]);' 'user&#')
pass=$(php -r 'echo rawurlencode($argv[1]);' 'pass@ ')
# Make sure to escape sed-specific characters within the string, as it will be
# embedded into sed script below! Note, we use `#` as a delimiter for substitution.
database="'mysql://${user}:${pass}@localhost/new_database'"
sed -i.bak -e 's#^\([[:space:]]*\$database[[:space:]]*=\).*;#\1 '"$database"';#' \
config.php
# With GNU sed
sed -i.bak -r 's#^(\s*\$database\s*=).*;#\1 '"$database"';#' config.php
输入
$database = 'mysql://custom_user:custom_password@localhost/custom_database';
$database = "mysql://custom_user:Pass&word@localhost/custom_database" ;
$database = "mysql://custom_user:Pass&word@localhost" . "/custom_" . "database" ;
输出
$database = 'mysql://user%26%23:pass%40%20@localhost/new_database';
$database = 'mysql://user%26%23:pass%40%20@localhost/new_database';
$database = 'mysql://user%26%23:pass%40%20@localhost/new_database';
script.pl
use strict;
use warnings;
my ($u, $p, $h, $d) = (shift, shift, shift, shift);
while (<>) {
my $uri = sprintf("'mysql://%s:%s@%s/%s'",
uri_escape($u),
uri_escape($p),
$h, $d);
s/^(\s*\$database\s*=).*;/"$1 ${uri};"/eg;
print;
}
<强>用法强>
perl -i.bak -MURI::Escape script.pl \
'user&#' 'pass@ ' 'localhost' 'new_database' config.php
如果我的猜测正确,并且您正在运行PHP,那么请考虑使用两个配置文件:
conf.php
,conf2.php
:PHP中最简单的实现可能如下所示。
conf.php
<?php
return [
'db' => [
'user' => 'default user',
'host' => 'default host',
],
];
conf2.php
<?php
$default = require('conf.php');
return array_replace_recursive($default, [
'db' => [
'user' => 'local user',
'host' => 'local host',
],
]);
test.php的
<?php
$conf = require('conf2.php');
var_dump($conf);
测试:
php test.php
输出
array(1) {
["db"]=>
array(2) {
["user"]=>
string(10) "local user"
["host"]=>
string(10) "local host"
}
}