在Perl脚本中,我们应该使用shell命令还是调用模仿shell操作的Perl函数?

Uno*_*nos 5 shell perl

我想知道这里的最佳做法.假设我想获取文件某些行的内容.我可以使用单行shell命令来获取我的答案,或编写子程序,如下面的代码所示.

一个名为的文本文件some_text:

She laughed. Then both continued eating in silence, like strangers,
but after dinner they walked side by side; and there sprang up
between them the light jesting conversation of people who are free
and satisfied, to whom it does not matter where they go or what
they talk about.
Run Code Online (Sandbox Code Playgroud)

用于获取文件第5行内容的代码

#!perl
use warnings;
use strict;

my $file = "some_text";
my $lnum = 5;
my $shellcmd = "awk 'NR==$lnum' $file";
print qx($shellcmd);
print getSrcLine($file, $lnum);

sub getSrcLine {
    my($file, $lnum) = @_;
    open FILE, $file or die "$!";
    my @ray = <FILE>;
    return $ray[$lnum-1];
}
Run Code Online (Sandbox Code Playgroud)

我问这个是因为我看到很多Perl脚本在某些时候调用了一个shell命令,而在稍后的某个时候,同样的任务是通过调用(库或手写)函数来完成的,例如,rm -rf相对于File::Path::rmtree.我只是想让它保持一致.

建议做什么?

bri*_*foy 14

如果有一个Perl函数用于操作,Perl认为你应该使用它的版本.但是,您举一个Perl 模块的示例,它提供了一种纯Perl方法.那是非常不同的.没有单一的答案(就像大多数情况一样),所以你必须自己决定做什么:

  • 纯Perl方法是否正确执行?例如,File :: Copy有一些限制,因为它为用户做出了一些尴尬的决定,所以很多人认为它已经被打破了.例如,请参阅File :: Copy与cp/mv.

  • 纯Perl方法是否在可接受的时间内完成?有时外部程序的速度要快几个数量级.有时它会慢得多.

  • 外部命令通常可以在一系列系统中移植(例如所有类似Linux的系统),但可能不是跨系列(例如Windows和Linux).您对此的容忍度可能会影响您的答案.即使您认为运行相同的命令,不同类型的类Unix系统也可能具有不同的操作开关.

  • 将复杂的参数 - 空格,引号和特殊字符 - 传递给外部命令会让你哭泣.你必须做很多繁琐的工作,以确保你正确处理论点.Perl子程序虽然不在乎.

  • 在使用外部命令时,您必须更加关注正在执行的操作.如果你只是打电话rm,Perl会搜索你的PATH并使用第一个调用的东西rm.这并不意味着它是你认为的程序.我在Mastering Perl的"安全编程技术"中写了很多相关内容.

  • 如果纯Perl方法需要一个模块,特别是如果该模块有许多复杂的依赖关系,那么你可能会依赖于它或者分发它.

就个人而言,我从纯粹的Perl方法开始,直到它不适用于这种情况.

对于您的特定示例,我将使用Perl.向awk倾斜,这是一个原型Perl,只是奇怪的.你应该能够做到perk所做的一切.如果您有一个awk程序,可以使用a2p程序将其转换为Perl :

 NR==5
Run Code Online (Sandbox Code Playgroud)

a2p将其转换为(在开始时模拟一些设置位):

while (<>) {
    print $_ if $. == 5;
}
Run Code Online (Sandbox Code Playgroud)

请注意,即使您有第五行,它仍会扫描整个文件.但是,您可以使用已翻译的程序作为开头:

while (<>) {
    if( $. == 5 ) {
        print;
        last;
        }
}
Run Code Online (Sandbox Code Playgroud)

我不认为你应该向其他一些程序掏空以避免使用Perl代码.

要删除目录树,我喜欢File :: Path.它有一些依赖项,但它们都在Perl标准库中.与该模块相关的疼痛很少(如果有的话).我会使用它,直到我遇到一个无效的问题.