skip to Main Content

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


  1. 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[x27Serversx27][$i][x27controlhostx27] = .*|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[x27Serversx27][$i][x27controlhostx27] = ).*|2x27hellox27;|' ./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.

    Login or Signup to reply.
  2. Using sed

    $ sed -E "~/* *(\$cfg.*['controlhost'][^']*')~s//1abc123/" input_file
    /* User used to manipulate with storage */
    $cfg['Servers'][$i]['controlhost'] = 'abc123';
    // $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';
    
    Login or Signup to reply.
  3. Cutting OP’s config file down to just the first section while adding a few lines to demonstrate handling of variable spacing and comments:

    $ cat config.php
    /* User used to manipulate with storage */
    // $cfg['Servers'][$i]['controlhost'] = '';
    //    $cfg['Servers'][$i]['controlhost'] = 'replace_me';
    //$cfg['Servers'][$i]['controlhost'] = 'replace_me';
      //    $cfg['Servers'][$i]['controlhost'] = 'replace_me';
        $cfg['Servers'][$i]['controlhost'] = 'replace_me';
    // $cfg['Servers'][$i]['controlport'] = '';
    // $cfg['Servers'][$i]['controluser'] = 'pma';
    // $cfg['Servers'][$i]['controlpass'] = 'pmapass';
    

    Placing our search and replacement patterns into bash variables:

    $ s1=Servers s2=controlhost rep=abc123
    

    One sed approach:

    sed -E "s|^([/ ]*)([$]cfg[[][^']*'${s1}'[^']+'${s2}'[^']+')([^']*)('.*)$|2${rep}4|" config.php
    

    Where:

    • -E – enable extended regex support; also allows designating capture groups without having to escape the parens
    • | – replace default sed script delimiter of / with |; eliminates need to escape / in patterns
    • need to wrap sed script in double quotes in order to reference the bash variables s1 / 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[ ([$] keeps bash from treating the $ as the start of a variable reference) while inserting bash variables s1 / 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 line
    • 2${rep}4 – rewrite line as [capture group #2] + bash variable rep + [capture group #4]

    An alternative where we combine capture groups #3/#4 into a single group that we’ll discard and replace with ' plus the bash variable rep plus ';:

    sed -E "s|^([/ ]*)([$]cfg[[][^']*'${s1}'[^']+'${s2}'[^']+)(.*)$|2'${rep}';|" config.php
    

    These both generate:

    /* User used to manipulate with storage */
    $cfg['Servers'][$i]['controlhost'] = 'abc123';
    $cfg['Servers'][$i]['controlhost'] = 'abc123';
    $cfg['Servers'][$i]['controlhost'] = 'abc123';
    $cfg['Servers'][$i]['controlhost'] = 'abc123';
    $cfg['Servers'][$i]['controlhost'] = 'abc123';
    // $cfg['Servers'][$i]['controlport'] = '';
    // $cfg['Servers'][$i]['controluser'] = 'pma';
    // $cfg['Servers'][$i]['controlpass'] = 'pmapass';
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search