在参数内使用单引号来递归系统bash调用

时间:2015-03-20 08:27:39

标签: perl shell quoting

我有一个Perl脚本progA.pl,需要使用progB.pl命令运行另一个Perl脚本system。但是,progB.pl中的~/.bashrc已有别名,因此我需要确保在加载~/.bashrc后运行它。我可以使用bash选项使用-lc来实现此目的。

对于这个问题,我考虑以下版本的progB.pl

,尽可能地简化问题。
use feature qw(say);
use strict;
use warnings;
use Data::Dump qw(dd dump);

say "Received \@ARGV: " . dump @ARGV;

这里是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\"" );

正在运行

$ progA.pl

给出输出:

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"

我们看到,在progB.pl直接运行而不使用bash -c时,此方法可以正常运行。当我使用bash -c运行命令时,三个备选方案都没有正常工作。

如何使用包含单引号的参数运行progB.pl并同时使用bash -c

2 个答案:

答案 0 :(得分:2)

你应该首先避免这种引用疯狂,但如果你坚持,你应该使用system ARRAY版本至少避免一个引用级别。

my $cmd = q{progB.pl --opt='This option contains '"'"'single'"'"' quotes'};
system( qw(bash -c), $cmd );

这只是引用疯狂的一个级别。

my $option = q{This option contains 'single' quotes} =~ s/'/'"'"'/gr; # '
my $cmd = qq{progB.pl --opt='$option'};
system( qw(bash -c), $cmd );

你可以做一些简单的帮手

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 );

答案 1 :(得分:0)

经过一些反复试验后,我到达了:

use feature qw(say);
use strict;
use warnings;

my $cmd = qq(print_first_arg.pl --opt='This option contains '"'"'single'"'"' quotes');
$cmd =~ s/'/'"'"'/g;
system( 'bash -c ' . "'$cmd'" );

对于这个测试案例,它似乎有效..

这也遵循@ysth在这个答案中建议的方法: https://stackoverflow.com/a/24869016/2173773