I'm trying to automate a manual installation of phpmyadmin and as part of this I'm trying to update settings in the configuration file.
Essentially I would like to be able to search for a specific string of text within the config.inc.php file whether it has a prefixed comment or not, remove the prefixed comment and insert/update the text between the single quotes.
For example I would like to find the following line
// $cfg['Servers'][$i]['controlhost'] = '';
and replace that line with
$cfg['Servers'][$i]['controlhost'] = 'abc123';
So far I've tried the following command but with no luck
sed 's|^\/\/ \[$cfg\['Servers'\]\[$i\]\['controlhost'\] = .*$|'abc123'|g' /var/www/html/example.com/phpmyadmin/config.inc.php
config.inc.php
/* User used to manipulate with storage */
// $cfg['Servers'][$i]['controlhost'] = '';
// $cfg['Servers'][$i]['controlport'] = '';
// $cfg['Servers'][$i]['controluser'] = 'pma';
// $cfg['Servers'][$i]['controlpass'] = 'pmapass';
/* Storage database and tables */
//$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
//$cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
// $cfg['Servers'][$i]['relation'] = 'pma__relation';
// $cfg['Servers'][$i]['table_info'] = 'pma__table_info';
// $cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
// $cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
// $cfg['Servers'][$i]['column_info'] = 'pma__column_info';
// $cfg['Servers'][$i]['history'] = 'pma__history';
// $cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
// $cfg['Servers'][$i]['tracking'] = 'pma__tracking';
// $cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
// $cfg['Servers'][$i]['recent'] = 'pma__recent';
// $cfg['Servers'][$i]['favorite'] = 'pma__favorite';
// $cfg['Servers'][$i]['users'] = 'pma__users';
// $cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
// $cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
// $cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
// $cfg['Servers'][$i]['central_columns'] = 'pma__central_columns';
// $cfg['Servers'][$i]['designer_settings'] = 'pma__designer_settings';
// $cfg['Servers'][$i]['export_templates'] = 'pma__export_templates';
Update 1
While surrounding the sed command with single quotes allows this to work, this doesn't allow variable expansion to work. For example if I declare a variable
phpmyadmin_host="localhost"
and then use this in the sed command surrounded with double quotes (to allow variable expansion) this doesn't work.
sed "s|\(\/\/ \)\($cfg\[\x27Servers\x27]\[$i]\[\x27controlhost\x27] = \).*|\2\x27${phpmyadmin_host}\x27;|" /var/www/html/example.com/phpmyadmin/config.inc.php
Update 2
After swapping all of the dollar signs for their hexadecimal counterpart which is \x24
sed "s|\(\/\/ \)\(\x24cfg\[\x27Servers\x27]\[\x24i]\[\x27controlhost\x27] = \).*|\2\x27${phpmyadmin_host}\x27;|" /var/www/html/example.com/phpmyadmin/config.inc.php
$cfg['Servers'][$i]['controlhost'] = 'localhost';
Update 3
For anyone wondering how to remove the double forward slashes comments no matter how many space characters follow in the first capture group you can use .*
From
sed "s|\(\/\/ \)\(capture_group_2\).*|\2|" /etc/some_file
to
sed "s|\(\/\/.*\)\(capture_group_2\).*|\2|" /etc/some_file
The full command would become
sed "s|\(\/\/.*\)\(\x24cfg\[\x27Servers\x27]\[\x24i]\[\x27controlhost\x27] = \).*|\2\x27${phpmyadmin_host}\x27;|" $phpmyadmin_configuration_file
You need to find a way to get the single quotes in there properly: How to escape single quote in sed? "\x27" is a suitable substitute.
For example, I copied the first four lines from your example into a file named "config.txt" and used this:
sed 's|// $cfg\[\x27Servers\x27\]\[$i\]\[\x27controlhost\x27\] = .*|hello|' ./config.txt
to get the output:
/* User used to manipulate with storage */
hello
// $cfg['Servers'][$i]['controlport'] = '';
// $cfg['Servers'][$i]['controluser'] = 'pma';
// $cfg['Servers'][$i]['controlpass'] = 'pmapass';
Also, you had a spurious "\[" before "$cfg" and you don't need to escape "]". "/" doesn't need to be escaped because "|" is being used as the separator.
I suspect that you would rather uncomment it and not type the entirety of the part before the "=" again, so you can use capture groups, like this:
sed 's|\(// \)\($cfg\[\x27Servers\x27]\[$i]\[\x27controlhost\x27] = \).*|\2\x27hello\x27;|' ./config.txt
to get:
/* User used to manipulate with storage */
$cfg['Servers'][$i]['controlhost'] = 'hello';
// $cfg['Servers'][$i]['controlport'] = '';
// $cfg['Servers'][$i]['controluser'] = 'pma';
// $cfg['Servers'][$i]['controlpass'] = 'pmapass';
Note that you need to escape each parenthesis for a capture group (Why do I need to escape regex characters in sed to be interpreted as regex characters?), and the "\2" represents the second capture group.