I have a Perl script progA.pl
which needs to run another Perl script progB.pl
using the system
command. However, progB.pl
has been aliased in ~/.bashrc
so I need to ensure that it is run after ~/.bashrc
has been loaded. I can achieve this by using bash
with the -lc
option.
For this question, I simplify the problem as much as I think is needed, by considering the following version of progB.pl
use feature qw(say);
use strict;
use warnings;
use Data::Dump qw(dd dump);
say "Received \@ARGV: " . dump @ARGV;
and here is progA.pl
:
use feature qw(say);
use strict;
use warnings;
use Data::Dump qw(dd dump);
my $cmd = qq(progB.pl --opt='This option contains '"'"'single'"'"' quotes');
say "cmd = " . dump($cmd);
system( "$cmd" );
say "-----";
system( 'bash -c ' . "$cmd" );
say "-----";
system( 'bash -c ' . "'$cmd'" );
say "-----";
system( "bash -c \"$cmd\"" );
Running
$ progA.pl
gives output:
cmd = "progB.pl --opt='This option contains '\"'\"'single'\"'\"' quotes'"
Received @ARGV: "--opt=This option contains 'single' quotes"
-----
Received @ARGV: ()
-----
Received @ARGV: "--opt=This"
-----
Received @ARGV: "--opt=This option contains single quotes"
We see that this works fine, when progB.pl
is run directly without using bash -c
. When I use bash -c
to run the command, none of the three alternatives are working correctly.
How can I run progB.pl
with an argument containing single quotes and at the same time using using bash -c
?
You should avoid this quoting madness at first place but if you insist, you should avoid at least one level of quoting by using system ARRAY
version.
my $cmd = q{progB.pl --opt='This option contains '"'"'single'"'"' quotes'};
system( qw(bash -c), $cmd );
It makes it only one level of quoting madness.
my $option = q{This option contains 'single' quotes} =~ s/'/'"'"'/gr; # '
my $cmd = qq{progB.pl --opt='$option'};
system( qw(bash -c), $cmd );
There you can make some simple helper
sub sq ($) { "'" . $_[0] =~ s/'/'"'"'/gr . "'" } # "
my $option = q{This option contains 'single' quotes};
my $cmd = qq{progB.pl --opt=@{[sq $option]}};
system( qw(bash -c), $cmd );