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[x27Serversx27][$i][x27controlhostx27] = ).*|2x27${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[x27Serversx27][x24i][x27controlhostx27] = ).*|2x27${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[x27Serversx27][x24i][x27controlhostx27] = ).*|2x27${phpmyadmin_host}x27;|" $phpmyadmin_configuration_file
3
Answers
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:
to get the output:
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:
to get:
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.
Using
sed
Cutting OP’s config file down to just the first section while adding a few lines to demonstrate handling of variable spacing and comments:
Placing our search and replacement patterns into
bash
variables:One
sed
approach:Where:
-E
– enable extended regex support; also allows designating capture groups without having to escape the parens|
– replace defaultsed
script delimiter of/
with|
; eliminates need to escape/
in patternssed
script in double quotes in order to reference thebash
variabless1 / s2 / rep
^([/ ]*)
– front of line plus [capture group #1] zero or more spaces or/
characters([$]cfg[[][^']*'${s1}'[^']+'${s2}'[^']+')
– [capture group #2] starts with literal string$cfg[
([$]
keepsbash
from treating the$
as the start of a variable reference) while insertingbash
variabless1 / s2
in the search and covering everything up to the leading single quote of the last quoted string([^']*)
– [capture group #3] anything within the last set of quotes('.*)$
– [capture group #4] everything from last quote to end of line2${rep}4
– rewrite line as [capture group #2] +bash
variablerep
+ [capture group #4]An alternative where we combine capture groups #3/#4 into a single group that we’ll discard and replace with
'
plus thebash
variablerep
plus';
:These both generate: