在Perl中实现CLI工具的最佳实践是什么?

Ana*_*dan 35 perl command-line

我正在使用Perl实现一个CLI工具.我们可以遵循哪些最佳做法?

DVK*_*DVK 37

作为序言,我花了3年时间在Perl工程并为一家大型金融公司实施了一个非常复杂的命令行工具集.以下想法基本上是我们团队设计指南的一部分.

用户界面

  1. 命令行选项:允许尽可能多的默认值.

  2. 没有任何具有2个以上选项的命令的位置参数.

  3. 有可读的选项名称.如果命令行的长度是非交互式调用的关注点(例如,一些未命名的遗留shell对命令行有短暂的限制),请提供短别名 - GetOpt :: Long可以轻松实现.

  4. 至少,在'-help'消息中打印所有选项的默认值.

    更好的是,打印所有选项的"当前"值(例如,如果参数和值与"-help"一起提供,帮助消息将从命令行打印参数值).这样,人们可以为复杂的命令组装命令行字符串,并在实际运行之前通过附加"-help"来验证它.

  5. 如果程序因错误而终止,请遵循退出非零返回代码的Unix标准约定.

  6. 如果您的程序可能产生有用的(例如值得捕获/ grepping/whatnot)输出,请确保将任何错误/诊断消息发送到STDERR,以便它们可以轻松分离.

  7. 理想情况下,允许用户通过命令行参数指定输入/输出文件,而不是强制"<"/">"重定向 - 这使得需要使用您的命令构建复杂管道的人的生活更简单.同上错误消息 - 有logfile选项.

  8. 如果一个命令有副作用,有一个"whatif/no_post"选项通常是一个非常好的主意.

履行

  1. 如前所述,不要重新发明轮子.使用标准命令行参数处理模块 - MooseX :: Getopt或Getopt :: Long

  2. 对于Getopt :: Long,将所有参数分配给单个哈希而不是单个变量.许多有用的模式包括将CLI args哈希传递给对象构造函数.

  3. 确保您的错误消息清晰且信息丰富......例如,包括"$!" 在任何与IO相关的错误消息中.在代码中花费额外的1分钟和2行是值得单独的"找不到文件"与"文件不可读"错误,而不是在生产紧急情况下花费30分钟,因为不可读的文件错误被生产误诊错误操作为"无输入文件" - 这是一个真实的例子.

  4. 不是特定于CLI,而是验证所有参数,理想情况下是在获取它们之后.CLI不允许像webapps这样的"前端"验证,所以要特别警惕.

  5. 如上所述,模块化业务逻辑.除了已经列出的其他原因之外,我必须将现有CLI工具重新实现为Web应用程序的次数是巨大的 - 如果逻辑已经是一个设计合理的perm模块,那就不那么困难了.

有趣的链接

CLI设计模式 - 我认为这是ESR

我记得我会尝试添加更多的子弹.


pot*_*tyl 21

使用POD记录您的工具,遵循联机帮助页的指导原则; 至少包括以下部分:名称,概要,描述,作者.一旦你有了正确的POD,就可以生成一个包含pod2man的手册页,在控制台上使用perldoc your-script.pl查看文档.

使用处理命令行选项的模块.我真的很喜欢将Getopt :: LongPod :: Usage一起使用,这样调用--help会显示一个很好的帮助信息.

如果成功与否,请确保脚本返回正确的退出值.

这是一个脚本的小骨架,可以完成所有这些:

#!/usr/bin/perl

=head1 NAME

simplee - simple program

=head1 SYNOPSIS

    simple [OPTION]... FILE...

    -v, --verbose  use verbose mode
    --help         print this help message

Where I<FILE> is a file name.

Examples:

    simple /etc/passwd /dev/null

=head1 DESCRIPTION

This is as simple program.

=head1 AUTHOR

Me.

=cut

use strict;
use warnings;

use Getopt::Long qw(:config auto_help);
use Pod::Usage;

exit main();

sub main {

    # Argument parsing
    my $verbose;
    GetOptions(
        'verbose'  => \$verbose,
    ) or pod2usage(1);
    pod2usage(1) unless @ARGV;
    my (@files) = @ARGV;

    foreach my $file (@files) {
        if (-e $file) {
            printf "File $file exists\n" if $verbose;
        }
        else {
            print "File $file doesn't exist\n";
        }
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为所有关于退出值的所有这些都不是一个好主意.在没有退出或死亡的情况下,Perl提供隐式退出(0).如果你在出现问题时死去,除此之外什么都不做,你就会得到一个表现良好的程序.我认为这个骨架将通过完全放弃主力来改善.Perl不是C. (11认同)
  • main函数的原因使它看起来很像C程序,如果没有它,你在程序中声明的所有变量都将成为全局词法范围的变量.使用"main"函数,所有内部变量都限定为该单个函数. (3认同)
  • 我认为任何使用“strict”的人都应该关心他们变量的范围。这是一个示例,为什么有些人可能喜欢在函数中插入所有代码。想象一下,整个程序没有在词法范围内隔离其变量,并且添加了一个新函数。如果新函数中的变量不是用“my”声明的变量,而它恰好存在于父作用域中,这将引起很多麻烦。在这种情况下,即使“使用严格”也无济于事。原因是因为程序将所有变量都变成了文件中的全局词法变量。 (2认同)

Bil*_*ill 13

我学到的一些教训:

1)始终使用Getopt :: Long

2)通过--help提供有关使用的帮助,最好是通过常见方案的示例.它可以帮助人们不知道或忘记如何使用该工具.(即,在六个月内).

3)除非对用户来说非常明显,否则不要长时间(> 5s)而不输出给用户.类似'print'的行$ row ... \n"除非($ row%1000)'走了很长的路.

4)对于长时间运行的操作,允许用户尽可能恢复.真的很难通过500万,死亡,重新开始.

5)将你正在做的事情的逻辑分成模块,并将实际的.pl脚本作为准系统保留; 解析选项,显示帮助,调用基本方法等等.你不可避免地会找到你想要重用的东西,这使得它变得更容易.

  • 对于3),**总是**为用户提供*-q*选项以保持安静 (2认同)

dra*_*tun 5

CPAN上有几个模块可以使编写CLI程序变得更加容易:


如果你的应用程序是Moose基础也看看MooseX :: GetoptMooseX :: Runnable


Ste*_*epp 5

最重要的是要有标准选项.

不要试图变得聪明,只要与现有工具保持一致.

如何实现这一点也很重要,但仅排在第二位.

实际上,这对所有CLI接口都非常通用.