Perl中的'''字符有什么作用?

thu*_*rmc 0 perl

我使用Perl来读取文件的每一行.我使用命令行工具来调用服务,我注意到一些有趣的功能,我无法弄清楚如何搜索.$cmd我为变量分配了调用服务的命令.如果我$cmd稍后在代码中引用它打印出命令行参数,但是如果我将其称为`$cmd`,则它会提供运行服务的输出.

对此有何解释?

tch*_*ist 8

它就像shell中的反引号一样,这就是为什么它被称为.有关详细信息,请参阅sh(1).它只捕获标准输出,而不是其他任何东西.它将$?变量设置为16位等待状态字.

这在perlop(1)手册页中都有解释:

qx/STRING/
`STRING`
一个字符串,它(可能)被内插,然后作为系统命令执行/bin/sh或与其等效.壳牌通配符,管道和重定向将受到尊重.返回收集的命令标准输出; 标准错误不受影响.在标量上下文中,它作为单个(可能是多行)字符串返回,如果命令失败则返回undef.在列表上下文中,返回行列表(但是您已使用$/$INPUT_RECORD_SEPARATOR定义行),如果命令失败,则返回空列表.

因为反引号不会影响标准错误:如果您需要解决此问题,请使用shell文件描述符语法(假设shell支持此语法).捕获命令STDERRSTDOUT合并在一起:

$output = `cmd 2>&1`;
Run Code Online (Sandbox Code Playgroud)

捕获命令STDOUT但丢弃它STDERR:

$output = `cmd 2>/dev/null`;
Run Code Online (Sandbox Code Playgroud)

捕获命令STDERR但丢弃它STDOUT (在此处排序很重要):

$output = `cmd 2>&1 1>/dev/null`;
Run Code Online (Sandbox Code Playgroud)

要交换一个命令STDOUT并且STDERR为了捕获它STDERR而将其留下STDOUT旧的STDERR:

$output = `cmd 3>&1 1>&2 2>&3 3>&-`;
Run Code Online (Sandbox Code Playgroud)

要分别读取命令STDOUT及其命令STDERR ,最简单的方法是将它们单独重定向到文件,然后在程序完成时从这些文件中读取:

 system("program args 1>program.stdout 2>program.stderr");
Run Code Online (Sandbox Code Playgroud)

STDIN命令使用的文件句柄继承自Perl STDIN.例如:

open(BLAM, "blam")     || die "$0: can't open blam: $!";
open (STDIN, "<&BLAM") || die "$0: can't dup BLAM: $!";
print `sort`;
Run Code Online (Sandbox Code Playgroud)

将打印文件的已排序内容blam.

使用单引号作为分隔符可以保护命令不受Perl的双引号插值的影响,而是将内容传递给shell:

$perl_info  = qx(ps $$);    # that's Perl's $$
$shell_info = qx'ps $$';    # that's the new shell's $$
Run Code Online (Sandbox Code Playgroud)

如何评估该字符串完全取决于系统上的命令解释程序.在大多数平台上,如果您希望对它们进行字面处理,则必须保护shell元字符.这在实践中很难做到,因为不清楚哪些角色需要逃脱,或者如何逃脱.见perlsec一个手动的清洁和安全的例子fork,并exec 安全地效仿反引号.在某些平台上(特别是类似DOS的平台),shell可能无法处理多行命令,因此在字符串中添加换行符可能无法满足您的需求.如果你的shell支持它(例如;在许多Unix shell上; &在Windows NT CMD.COM shell上),你可以通过用命令分隔符分隔它们来在一行中评估多个命令.

从v5.6.0开始,Perl尝试在启动子进程之前刷新为输出打开的所有文件,但在某些平台上可能不支持这一点(请参阅perlport(1)).为安全起见,您可能需要设置$|($AUTOFLUSH英文)或在任何打开的句柄上调用IO :: Handleautoflush方法.

请注意,某些命令shell可能会限制命令行的长度.必要时,必须确保字符串在任何必要的插值后不超过此限制.有关特定环境的更多详细信息,请参阅特定于平台的发行说明.

使用此运算符可能会导致难以移植的程序,因为调用的shell命令在系统之间有所不同,实际上根本不存在.作为一个示例,该类型下的POSIX外壳命令是从一不同类型 DOS下命令.这并不意味着当他们成为完成某件事的正确方法时,你应该尽量避免反击.Perl被认为是一种粘合语言,它粘合在一起的东西之一就是命令.只要了解你自己的成就.

有关更多讨论,请参阅I/O运算符.

这是一个使用反引号来获取管道中第一个元素的退出状态的简单示例:

$device = q(/dev/rmt8);
$dd_noise = q(^[0-9]+\+[0-9]+ records (in|out)$);
$status = `exec 3>&1; ((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) |  egrep -v "$dd_noise" 1>&2 3>&- 4>&-) 4>&1`;
Run Code Online (Sandbox Code Playgroud)

编辑

好吧那么,也许这不是一个简单的例子.:)但是这个是.

我想建议使用Capture :: Tiny CPAN模块作为一种更简单的方法来管理通常使用反引号运行的外部命令的输出.它有优点和缺点,但我觉得对许多人来说,优点胜过任何可论证的劣势

  • 好处是,你能做到这一切,而不需要文件描述符重定向的神秘谜团的方式在前面的例子做了深入的了解.

  • 缺点是它的又一非核心的依赖-别的东西,你必须从CPAN安装.

这对你得到的东西来说真的不错.

这是一个多么容易的例子:

名称

Capture :: Tiny - 从Perl, XS或外部程序捕获STDOUT和STDERR

概要

    use Capture::Tiny qw/capture tee capture_merged tee_merged/;

     ($stdout, $stderr) = capture {
        # your code here
      };

     ($stdout, $stderr) = tee {
        # your code here
      };

     $merged = capture_merged {
        # your code here
      };

     $merged = tee_merged {
        # your code here
      };
Run Code Online (Sandbox Code Playgroud)

描述

Capture :: Tiny提供了一种简单,可移植的方式来捕获发送到STDOUT或STDERR的任何内容,无论它是来自Perl,来自XS代码 还是来自外部程序.可选地,可以输出输出,以便在传递到原始句柄时捕获输出.是的,它甚至适用于Windows.停止猜测在任何特定情况下使用十几个捕获模块中的哪一个并且只使用这个.

在那里,是不是更容易?