0

I have two php file that will replaced by sed

first one is

$db['default'] = array(
    'dsn' => '',
    'hostname' => 'localhost',
    'username' => 'demo',
    'password' => 'demopass',
    'database' => 'dbname'
);

I need to replace dbname to dynamic variables from shell script I using this script and working

sed -i -e "/.*'database' =>*./ s/.*/'database' => '$1',/" /var/www/project/application/config/database.php

The second file is

$config['timezone'] = 'Asia/Jakarta';
$config['sess_cookie_name'] = 'sess_project';

I need to change 'Asia/Jakarta' to another dynamic variables, but its not working since it has $ sign in the beginning. this is my code

sed -i -e "/.*$config['timezone'] = *./ s/.*/$config['timezone'] = '$2';/" /var/www/project/application/config/config.php

Thank you

3 Answers3

2

This is actually more interesting than it at first appears.

At least with GNU sed, it appears that $ is only treated as a regular expression metacharacter when it appears at the end of a pattern. So for example whereas:

$ echo 'config$' | sed 's/config$/foobar$/'
config$

needs to be

$ echo 'config$' | sed 's/config\$/foobar$/'
foobar$

the $ in

$ echo '$config' | sed 's/$config/$foobar/'
$foobar

works without escaping. However, because you've used weak (double) quotes around the sed expression to permit inclusion of literal single quotes, you need to escape the $ in $config to prevent the shell expanding it (to a presumably empty value). Because it's the shell that's doing the expansion, it also needs to be escaped on the RHS of the replacement (where it wouldn't have been treated as a regex metacharacter).

On the other hand, [ (which is not special to the shell when double quoted) is treated as a regex metacharacter regardless of position, and needs to be escaped for that reason - while ] doesn't need to be escaped when it isn't preceded by (unescaped) [.

Finally, if the expansion of $2 may contain a forward slash (like the Asia/Jakarta that it replaces), then that must also be escaped - or you must change the sed delimiter to a different character.

So given

$ cat config.php
$config['timezone'] = 'Asia/Jakarta';
$config['sess_cookie_name'] = 'sess_project';

and

var='North America/Chicago'

then

$ sed -e "/.*\$config\['timezone'] = .*/ s/.*/\$config['timezone'] = '${var//\//\\\/}';/" config.php
$config['timezone'] = 'North America/Chicago';
$config['sess_cookie_name'] = 'sess_project';

(note that I also corrected the presumed type *. to .*), or more simply

sed -e "/\$config\['timezone']/ s/=.*/= '${var//\//\\\/}';/" config.php

References:

  1. What characters do I need to escape when using sed in a sh script?
  2. Sed find and replace with slashes
steeldriver
  • 81,074
0

Your sed seems overcomplicated. I suggest (assuming this script is called t):

!/bin/bash
sed -i -e "s~\$config['timezone']\s*=\s*'.*';~\$config['timezone'] = '$1';~i" /var/www/project/application/config/config.php

And invoke it like this: ./t 'Asia/Novokuznetsk'. Note that the slash is not escaped, due to regex delimiter ~. The dollar signs are escaped, except in $1.

0
repl_rhs=$(printf '%s\n' "$1" | sed -e 's:[\&/'\'']:\\&:g')
sed -e "
  /\(\$config[[]'timezone'] =\).*/s//\1 '$repl_rhs'/
" file.php
  • escape the rhs metaharacters + s/// delimiter+ php single quoted string
  • no newline in the replacement string $1