使用bash脚本更改文件中的数据库连接详细信息

时间:2016-12-12 13:49:27

标签: shell awk sed

我在设置文件中有以下数据库连接行:

$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的回答,因为他是第一个提出工作代码的人。

同样,这个问题根本不是关于如何构建像密码这样的输入数据。

2 个答案:

答案 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。

SED

根据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';

的Perl

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

如果我的猜测正确,并且您正在运行PHP,那么请考虑使用两个配置文件:

    代码库中的
  • conf.php
  • server-local,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"
  }
}