Home > Software design >  Calling sed within perl with a variable
Calling sed within perl with a variable

Time:09-27

I would like to inplace edit ssd_config file where i need to replace the #Port to a custom port.

Before:

#Port <portnum>

 ex: #Port 22

After:

Port <customport>

ex: Port 2022

Here the custom port is coming in a variable $port.

I tried the below script but does nothing.

my $prt = "Port 2022";
my $cmd = "sed -i \'s/#Port [0-9]\ /$prt/g\' sshd_config";
system($cmd);

Tried even with tick operator.

`sed -i \"s/#Port [0-9]\ /\$prt/g\" sshd_config`;

CodePudding user response:

system("sed ....") is invoking a shell to parse the command line, which means that everything needs to be properly escaped according to the rules of the shell. This together with string escaping inside Perl makes it hard to get right. A much simpler way is to skip the shell and call sed directly and also use string concatenation to add the $prt at the right place (and don't forget to also include the "Port" string itself since you want to have it in the output):

 system('sed','-i','s/#Port [0-9] /Port ' . $prt . '/', 'sshd_config');

Alternatively one could do it in Perl directly, i.e. something like this:

 open(my $fh,'<','sshd_config') or die $!;
 my @lines = map { s/#Port \d /Port $prt/ } <$fh>;
 open($fh,'>','sshd_config') or die $!;
 print $fh @lines;
 close($fh);

This is a bit longer but does not rely on starting an external program and is thus faster. And if there is more to do than a simple replacement it is also more flexible.

CodePudding user response:

I'd suggest to do all that in Perl, once you are running a Perl program. That way one doesn't have to run external programs, not to mention the benefits of not having to mess with all the quoting and escaping if you actually need a shell (not in the shown example though).

Then we need a few more lines of code, to read the file and and edit its content and write it back out. That shouldn't matter, given all the benefits -- but there are libraries that cut out even that as well, for example the very handy Path::Tiny

use Path::Tiny;

...

path($filename)->edit_lines( sub { s/#Port [0-9] /Port $prt/ } );

I take it that $filename and $prt have been introduced earlier in the program.

There is also a edit method, which slurps the whole file.

  • Related