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

我正在使用Perl实现一个CLI工具。 我们可以在这里遵循的最佳做法是什么?

作为前言,我花了3年的时间为一家大型金融公司devise和实现了一个非常复杂的Perl命令行工具集。 下面的想法基本上是我们团队devise准则的一部分。

用户界面

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

  2. 没有超过2个选项的任何命令的位置参数。

  3. 有可读的选项名称。 如果命令行的长度是非交互式调用的关注点(例如,某些未命名的传统shell在命令行上有较短的限制),请提供简短的别名–GetOpt :: Long可以轻松实现。

  4. 至less,在“-help”消息中打印所有选项的默认值。

    更好的是,打印所有选项的“当前”值(例如,如果参数和值与“-help”一起提供,则帮助消息将从命令行打印参数值)。 这样,人们可以为复杂的命令组装命令行string,并在实际运行之前通过追加“-help”来进行validation。

  5. 遵循Unix的标准惯例,如果程序以错误终止,则使用非零返回码退出。

  6. 如果你的程序可能会产生有用的(如值得捕获/ grepping / whatnot)输出,确保任何错误/诊断消息去STDERR,所以他们很容易分开。

  7. 理想情况下,允许用户通过命令行参数指定input/输出文件,而不是强制使用“<”/“>”redirect – 这使得需要使用命令构build复杂pipe道的人员的生活更加简单。 同上的错误信息 – 有日志文件选项。

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

履行

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

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

  3. 确保你的错误信息是清晰的和翔实的…例如,包括“$!” 在任何IO相关的错误信息。 值得花费额外的1分钟和2行代码,以便有一个单独的“文件未find”与“文件不可读”错误,而不是在生产紧急情况下花费30分钟,因为不可读的文件错误被错误诊断作为“没有input文件”的操作 – 这是一个真实的例子。

  4. 不是特定的CLI,而是validation所有参数,理想的是在获得它们之后。 CLI不允许像webapps那样进行“前端”validation,所以要特别警惕。

  5. 如上所述,模块化业务逻辑。 除了已经列出的其他原因,我不得不重新实现一个现有的CLI工具作为一个Web应用程序的数量是巨大的 – 如果逻辑已经是一个适当devise的perm模块并不难。

有趣的链接

CLIdevise模式 – 我认为这是ESR的

我会尝试添加更多的子弹,我记得他们。

使用POD来logging您的工具,遵循手册的指导原则; 至less包括以下部分:名称,概要,说明,作者。 一旦你有适当的POD,你可以用pod2man生成一个手册页,在perldoc your-script.pl的控制台上查看文档。

使用为您处理命令行选项的模块。 我真的很喜欢使用Getopt :: Long与Pod :: 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; } 

我学到的一些教训:

1)总是使用Getopt :: Long

2)通过–help提供使用方面的帮助,理想情况下是常见场景的例子。 它有助于人们不知道或忘记如何使用该工具。 (也就是六个月)。

3)除非用户很明白为什么不长时间(> 5s)而不输出给用户。 像“打印”行$行… \ n“除非($行%1000)'走了很长的路要走。

4)对于长时间运行的操作,允许用户尽可能恢复。 它真的很难通过一百万五十万,死亡,并重新开始。

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

最重要的是要有标准的select

不要试图聪明 ,只要与现有的工具保持一致。

如何实现这一点也是重要的 ,但只有第二

实际上,这对于所有的CLI接口来说都是相当通用的。

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

  • 应用:: CLI
  • 应用:: Cmd的

如果你的应用程序是基于Moose的,还可以看看MooseX :: Getopt和MooseX :: Runnable

以下几点不是特定于Perl的,但是我发现许多Perl CL脚本在这些方面有缺陷:

  1. 使用常用命令行选项。 显示版本号执行-v或–version不是–ver。 对于recursion处理-r(或者-R虽然在我的Gnu / Linux经验中更常见),而不是–rec。 如果人们记得参数,人们会使用你的脚本。 如果你能记住“它像grep一样工作”或者其他一些熟悉的工具,学习一个新的命令是很容易的。

  2. 许多命令行工具在“当前目录”中处理“事物”(文件或目录)。 虽然这可以很方便,但也要确保你也添加了命令行选项来明确识别要处理的文件或目录。 这样可以更容易地将你的工具放在pipe道中,而不需要开发人员发出一堆cd命令,并记住它们在哪个目录中。

您应该使用Perl模块来使您的代码可重用并易于理解。
应该看看Perl的最佳实践