Perl 将 '<' 视为常规字符,而不是输出重定向

Posted

技术标签:

【中文标题】Perl 将 \'<\' 视为常规字符,而不是输出重定向【英文标题】:Perl is respecting '<' as a regular character rather an output redirectionPerl 将 '<' 视为常规字符,而不是输出重定向 【发布时间】:2016-10-21 17:29:28 【问题描述】:

我需要一些帮助来解决这个特殊的编码问题。

我有一个调用另一个 perl 脚本 (#2) 的 perl 脚本 (#1)。在 #1 中,我调用 #2 也将其输出重定向到日志文件。像这样

my @command = ('downloadImage', '-url', $url, '>', $log);

此命令在终端上运行时运行良好。 我是否必须使用其他类型的特殊字符来告诉 perl > 是输出重定向而不仅仅是一些常规字符?

我是这样运行的:

system(@command);

【问题讨论】:

你是如何执行@command的? 【参考方案1】:

我假设完整的代码是:

my @command = ('downloadImage', '-url', $url, '>', $log);
system @command;

system 有两种模式。 system $command 将在 shell 中运行 $command

# This will write 'foo' to the file 'bar'
system "echo foo > bar";

system @command 真的是system $program, @args。它将绕过 shell 并运行 $program@args

# This will print 'foo > bar'
system "echo", "foo", ">", "bar"

所以如果你想像这样进行输出重定向,你可以将@command 一起加入。

system join " ", @command;

但这可能会遇到 shell 引用问题。在 Perl 中使用 piped open 自己进行重定向更安全、更快、更便携。

use strict;
use warnings;
use autodie;

open my $echo, "-|", "echo", "foo";
open my $log, ">", "some.log";

print $log <$echo>;

【讨论】:

提示:print $log $_ while &lt;$echo&gt;; 减少了内存开销。【参考方案2】:

在做

system('downloadImage', '-url', $url, '>', $log)

在 Perl 中是一样的

'downloadImage' '-url' "$url" '>' "$log"

在外壳中。这将使用四个参数执行downloadImage,其中一个是&gt;。您尝试执行的 shell 命令如下:

'downloadImage' '-url' "$url" > "$log"

如果你想执行那个 shell 命令,你首先需要一个 shell。以下是您应该如何实现这一目标:

use String::ShellQuote qw( shell_quote );

my @cmd = ('downloadImage', '-url', $url);

my $shell_cmd = shell_quote(@cmd) . ' >' . shell_quote($log);
system($shell_cmd);  # Short for system('/bin/sh', '-c', $shell_cmd);

但是,使用 shell 有很多缺点。以下是一些替代方案:

use IPC::Open3 qw( open3 );

my @cmd = ('downloadImage', '-url', $url);


   open(local *CHILD_STDIN, '<', '/dev/null')
      or die("Can't open \"/dev/null\": $!\n");

   open(local *CHILD_STDOUT, '>', $log)
      or die("Can't create \"$log\": $!\n");

   my $pid = open3('<&CHILD_STDIN', '>&CHILD_STDOUT', '>&STDERR', @cmd);
   waitpid($pid, 0);

use IPC::Run3 qw( run3 );

my @cmd = ('downloadImage', '-url', $url);

run3(\@cmd, \undef, $log);

use IPC::Run qw( run );

my @cmd = ('downloadImage', '-url', $url);

run(\@cmd, '<', '/dev/null', '>', $log);

【讨论】:

(我只包括了 IPC::Open3,因为它与 Perl 捆绑在一起。老实说,对于大多数用途来说,它的级别太低了。)

以上是关于Perl 将 '<' 视为常规字符,而不是输出重定向的主要内容,如果未能解决你的问题,请参考以下文章

如何强制将变量视为 perl 中的字符串?

我想知道是不是有任何方法可以将引号内的分隔符仅视为字符而不是分隔符

将 c++ 字符串视为指针

BigQuery 加载 - NULL 被视为字符串而不是空

如何将符号链接视为Mercurial中的目录?

perl的基本代码