0

I'm pretty close to my goal, but I am stuck at this point.

I'm trying to create an automation script that does some simple editing of the phpmyadmin config file.

cat /usr/share/phpmyadmin/config.sample.inc.php |sed s^//\ \$cfg\\[\'Servers\'^\$cfg\\[\'Servers\'^

Basically I'm trying to remove the // in all the lines that start with // $cfg['Servers']. The above line does indeed do that, but I'm unhappy with all the escaping that I had to do. I've tried hundreds of variations of this sed command, but escaping all those other characters seemed to be the only method that worked so far.

The other snag is: Eventually I want to pass the above command string through an elevated shell (using sudo sh -c), such as:

sudo sh -c "cat /usr/share/phpmyadmin/config.sample.inc.php |sed s^//\ \$cfg\\[\'Servers\'^\$cfg\\[\'Servers\'^  >/usr/share/phpmyadmin/config.inc.php"

but every time I try to do that, I get this error:

sed: -e expression #1, char 27: unterminated `s' command

So my question is: Can I simplify my sed expression such that I don't need to escape so many characters, and how do I pass this to an elevated shell so it doesn't break my sed s command?

I think my main issue is the the elevated shell is passed a string deliminated by double quotes and the sed string contains single quotes. In the past I generally didn't have commands that used both so I would be able to substitute one for the other.

2

No need to escape whitespace and single-quotes if the script is properly enclosed in double-quotes:

sed "s^// \$cfg\['Servers'^\$cfg['Servers'^" file

Also, the bracket in the replacement does not need to be escaped. The bracket in the regex does need to be escaped, because otherwise it is understood as a special regex symbol.

To reduce the escaping to the greatest extent, the best is to put the sed command in a file, so we do not need the double-quotes and do not need to protect the dollar sign $ in the replacement from shell expansion.

servers.sed:

s^// \$cfg\['Servers'^$cfg['Servers'^

Then run it this way:

sed -f servers.sed file

This last form is also very easy to use in an elevated shell:

sudo sh -c 'sed -f servers.sed file > newfile'
1
  • Thanks for the tips. Your method does do what I was looking for. Since this is going to be a a larger automation script, I assume the best way is to just create the "server.sed" file with in the script itself (echo "s^// \$cfg['Servers'^$cfg['Servers'^" > servers.sed) and then deleted the file from within the script after I've used it. Is there a better way to handle that? Jul 2 '20 at 16:57
0

Here are a couple of observations that might help simplify matters.

There is no need to cat a file and then present it to sed on it's stdin. sed can just as well take a filename on it's argument list or use the < operator.

Don't take it as your responsibility to quote the characters on the commandline. This is the job of the shell if you enclose the command within quotes.

Now since single quotes are already present in the sed command so it is easy if you use the double quotes.

  • But then we need to turn off the $ character from being interpreted by the shell under double quotes interpolation.
  • The bracket [ needs quoting in anticipation of it to be interpreted as a literal by sed.

That took care of the shell aspect. let's look at the sed command now.

Here you are needlessly duplicating the replacement portion. As your goal is only to strip the leading double slash we should be using the /selectline/s/pat/repl/form of the s/// command.

Since the line is already selected, we know what the first 3 characters are: // and a space.

There is a subtle bug lurking in the sed command. Since you chose to use the ^ as the substitution command delimiter, it no longer functions as the beginning-of-line character.

In regex terms what this means is that a double slash at any place in the line is a candidate for change. Obviously this is not what your spec says. So we use a different delimiter |

 base=/usr/share/phpmyadmin
 if=$base/config.sample.inc.php
 of=$base/config.inc.php
 < "$if" \
    sed -e "\\|^// \$cfg\\['Servers']|s/...//" \
 > "$of" 

you can also use the single quoted sed command line to slightly reduce the backslash load:

sed -e '\|^// $cfg\['\''Servers'\'']|s/...//' 

Now coming to the sudo part. You are passing the sed command as a string to the shell interpreter. Instead we can pass the command on the shell's stdin via the heredoc << operator.

sudo sh <<\eof
base=/usr/share/phpmyadmin
if=$base/config.sample.inc.php
of=$base/config.inc.php
< "$if" sed -e "\\|^// \$cfg\\['Servers']|s/...//" > "$of"
eof

HTH

P.S i have not tested it as i am away from my terminal.

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.