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

4
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
1
  • Thank you for the explanation and this is working as expected. Yeah it's so tricky because I was mixed up shell and regex things Oct 9 '20 at 0:58
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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.