我想在perl中运行shell命令如下:
tar --exclude="*/node_modules" \
--exclude="*/vendor" \
--exclude='.git' \
-zvcf /tmp/robot.tgz .
Run Code Online (Sandbox Code Playgroud)
但似乎perl无法执行此操作:
`tar --exclude="cv/node_modules" \
--exclude="*/vendor" \
--exclude='.git' \
-zvcf /tmp/robot.tgz .`;
Run Code Online (Sandbox Code Playgroud)
这是错误:
tar: Must specify one of -c, -r, -t, -u, -x
sh: line 1: --exclude=*/vendor: No such file or directory
sh: line 2: --exclude=.git: command not found
sh: line 3: -zvcf: command not found
Run Code Online (Sandbox Code Playgroud)
似乎perl将每一行视为一个命令.
我道歉.我原来的诊断错了
在这样的帖子中很难清楚地表达包含Perl转义字符的字符串的内容.如果您不清楚以下任何内容,请写下评论来说明.我希望我没有让事情变得不必要地复杂化
我下面的原始解决方案仍然有效,并且可以让您更好地控制命令的内容,但是我为什么OP的代码对他们不起作用的原因是错误的,并且真相提供了其他解决方案
的问题是,反引号(或内容qx/.../)的作为评价双引号字符串,这意味着Perl的变量和逸出样序列\t和\x20在执行字符串之前被扩展.其中一个后果是,如果后跟一个文字换行符,则删除反斜杠,只留下换行符
这意味着像这样的声明
my $output = `ls \
-l`;
Run Code Online (Sandbox Code Playgroud)
将被预处理"ls \n-l"并且将不再包含向shell发出应该删除换行所需的反斜杠(或者实际上是首先将命令传递给shell)
除了我在下面的原始帖子中描述的直接操作命令字符串外,还有两种解决方案.第一种是通过将其加倍来逃避反斜杠本身,就像这样
my $output = `ls \\
-l`;
Run Code Online (Sandbox Code Playgroud)
这将防止它被Perl删除.这会将反斜杠换行序列传递给shell,这将正常删除它
另一种是使用qx'...'单引号分隔符而不是反引号,这将阻止内容被处理为双引号字符串
my $output = qx'ls \
-l';
Run Code Online (Sandbox Code Playgroud)
除非您在要插入的字符串中使用了Perl变量,否则这将正常工作
问题是shell在执行之前从命令字符串中删除了前缀为反斜杠的换行符.没有该步骤,命令无效
所以你必须自己在Perl中做同样的事情,为此你必须把命令放在一个临时变量中
use strict;
use warnings 'all';
my $cmd = <<'END';
tar --exclude="*/node_modules" \
--exclude="*/vendor" \
--exclude='.git' \
-zvcf /tmp/robot.tgz .
END
$cmd =~ s/\\\n//g;
my $output = `$cmd`;
Run Code Online (Sandbox Code Playgroud)
当然不需要反斜杠; 您可以在执行命令之前简单地使用换行符并删除它们
或者您可能更喜欢将操作包装在子例程中,如下所示
use strict;
use warnings 'all';
my $output = do_command(<<'END');
tar --exclude="*/node_modules" \
--exclude="*/vendor" \
--exclude='.git' \
-zvcf /tmp/robot.tgz .
END
sub do_command {
my ($cmd) = @_;
$cmd =~ s/\\\n//g;
`$cmd`;
}
Run Code Online (Sandbox Code Playgroud)