如何在perl中执行multiline shell命令?

时间:2016-04-26 03:02:38

标签: perl shell

我想在perl中运行shell命令:

var englishTomRNA: [Character: [String]] = ["A": ["UUU", "UAC"],
                                            "Q": ["UUA"],
                                            "S": ["UCU", "UCC", "UCA"]]

var mRNAtoEnglish = [String:Character]()
for (key, value) in englishTomRNA {
    for mRNA in value {
        mRNAtoEnglish[mRNA] = key
    }
}

print(mRNAtoEnglish)
// ["UUU": "A", "UCA": "S", "UCC": "S", "UAC": "A", "UUA": "Q", "UCU": "S"]

但似乎perl无法执行此操作:

tar --exclude="*/node_modules" \
--exclude="*/vendor" \
--exclude='.git' \
-zvcf /tmp/robot.tgz .

这是错误:

`tar --exclude="cv/node_modules" \
--exclude="*/vendor" \
--exclude='.git' \
-zvcf /tmp/robot.tgz .`;

似乎perl将每一行视为一个命令。

1 个答案:

答案 0 :(得分:8)

更新

我道歉。我原来的诊断错了

很难在这样的帖子中清楚地表达包含Perl转义字符的字符串的内容。如果您不清楚以下任何内容,请写下评论来说明。我希望我没有让事情变得不必要的复杂化

我在下面的原始解决方案仍然有效,并且可以让您更好地控制命令的内容,但是我为什么OP代码不能为他们工作的原因是错误的,而且事实是真的提供其他决议

问题是反引号(或qx/.../)的内容被评估为双引号字符串,这意味着Perl变量和转义序列如\t和在执行字符串之前展开\x20。其中一个后果是,如果后面跟着一个文字换行符,则会删除反斜杠,只留下换行符

这意味着像这样的声明

my $output = `ls \
-l`;

将被预处理到"ls \n-l"并且将不再包含向shell发出应该删除换行符所需的反斜杠(或者实际上是首先将命令传递给shell)< / p>

除了我在下面的原始帖子中描述的直接操作命令字符串外,还有两种解决方案。第一个是通过将其加倍来逃避反斜杠本身,就像这个

my $output = `ls \\
-l`;

将阻止它被Perl删除。这会将反斜杠换行序列传递给shell,这将正常删除它

另一种方法是使用qx'...'而不是反引号和单引号分隔符,这将阻止内容被处理为双引号字符串

my $output = qx'ls \
-l';

除非您在要插补的字符串中使用了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`;

当然不需要反斜杠;您可以在执行命令之前简单地使用换行符并删除它们

或者您可能更喜欢将操作包装在子例程中,例如

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`;
}