重要的
该仓库已移至 https://github.com/dart-lang/core/tree/main/pkgs/args
将原始命令行参数解析为一组选项和值。
该库支持 GNU 和 POSIX 样式选项,并且适用于服务器端和客户端应用程序。
首先创建一个 ArgParser:
var parser = ArgParser();
然后使用 addOption() 和 addFlag() 在该解析器上定义一组选项。这是创建名为“name”的选项的最小方法:
parser.addOption('name');
当选项只能设置或取消设置(而不是采用字符串值)时,请使用标志:
parser. addFlag ( 'name' );
默认情况下,标志选项接受“no-”前缀来否定该选项。您可以使用negatable
参数禁用“no-”前缀:
parser. addFlag ( 'name' , negatable : false );
注意:从现在开始,“选项”指的是常规选项和标志。在区分很重要的情况下,我们将使用“非标志选项”。
选项可以有一个可选的单字符缩写,用abbr
参数指定:
parser. addOption ( 'mode' , abbr : 'm' );
parser. addFlag ( 'verbose' , abbr : 'v' );
选项还可以有一个默认值,通过defaultsTo
参数指定。当参数未指定选项时,将使用默认值。
parser. addOption ( 'mode' , defaultsTo : 'debug' );
parser. addFlag ( 'verbose' , defaultsTo : false );
非标志选项的默认值可以是任何字符串。对于标志,它必须是bool
。
要验证非标志选项,您可以使用allowed
参数来提供允许的值集。当您这样做时,如果选项的值不在允许的集合中,解析器将抛出ArgParserException
。以下是指定允许值的示例:
parser. addOption ( 'mode' , allowed : [ 'debug' , 'release' ]);
您可以使用callback
参数将函数与选项关联起来。稍后,当进行解析时,将使用选项的值调用回调函数:
parser. addOption ( 'mode' , callback : (mode) => print ( 'Got mode $ mode ' ));
parser. addFlag ( 'verbose' , callback : (verbose) {
if (verbose) print ( 'Verbose' );
});
每当解析一组参数时,就会调用所有选项的回调。如果参数中未提供选项,则其回调将传递默认值;如果未设置默认值,则传递null
。
如果某个选项是mandatory
但未提供,则结果对象在检索时会抛出 [ ArgumentError
][ArgumentError]。
parser. addOption ( 'mode' , mandatory : true );
一旦你用一些选项和标志设置了 ArgParser,你就可以通过使用一组参数调用 ArgParser.parse() 来使用它:
var results = parser. parse ([ 'some' , 'command' , 'line' , 'args' ]);
这些参数通常来自main()
参数。例如:
main(List<String> args) {
// ...
var results = parser.parse(args);
}
但是,您可以传入任何字符串列表。 parse()
方法返回 ArgResults 的实例,这是一个类似地图的对象,包含已解析选项的值。
var parser = ArgParser ();
parser. addOption ( 'mode' );
parser. addFlag ( 'verbose' , defaultsTo : true );
var results = parser. parse ([ '--mode' , 'debug' , 'something' , 'else' ]);
print (results. option ( 'mode' )); // debug
print (results. flag ( 'verbose' )); // true
默认情况下, parse()
方法允许在位置参数之后传递附加标志和选项,除非使用--
来指示所有其他参数都将是位置参数。位置参数进入 ArgResults.rest。
print (results.rest); // ['something', 'else']
要在找到位置参数后立即停止解析选项,请在创建 ArgParser 时allowTrailingOptions: false
。
要实际在命令行上传递选项和标志,请使用 GNU 或 POSIX 风格。考虑这个选项:
parser. addOption ( 'name' , abbr : 'n' );
您可以使用以下任意命令在命令行上指定其值:
--name=somevalue
--name somevalue
-nsomevalue
-n somevalue
考虑这个标志:
parser. addFlag ( 'name' , abbr : 'n' );
您可以使用以下方法之一将其设置为 true:
--name
-n
您可以使用以下命令将其设置为 false:
--no-name
多个标志缩写可以折叠成一个参数。假设您定义了这些标志:
parser
.. addFlag ( 'verbose' , abbr : 'v' )
.. addFlag ( 'french' , abbr : 'f' )
.. addFlag ( 'iambic-pentameter' , abbr : 'i' );
您可以一次设置所有三个标志:
-vfi
默认情况下,一个选项只有一个值,后面的选项值会覆盖前面的选项值;例如:
var parser = ArgParser ();
parser. addOption ( 'mode' );
var results = parser. parse ([ '--mode' , 'on' , '--mode' , 'off' ]);
print (results. option ( 'mode' )); // prints 'off'
可以使用addMultiOption()
解析多个值。使用此方法,一个选项可以出现多次,并且parse()
方法返回一个值列表:
var parser = ArgParser ();
parser. addMultiOption ( 'mode' );
var results = parser. parse ([ '--mode' , 'on' , '--mode' , 'off' ]);
print (results. multiOption ( 'mode' )); // prints '[on, off]'
默认情况下,多值选项的值也可以用逗号分隔:
var parser = ArgParser ();
parser. addMultiOption ( 'mode' );
var results = parser. parse ([ '--mode' , 'on,off' ]);
print (results. multiOption ( 'mode' )); // prints '[on, off]'
可以通过传递splitCommas: false
来禁用此功能。
除了选项之外,您还可以定义命令。命令是一个命名参数,有自己的一组选项。例如,考虑以下 shell 命令:
$ git commit -a
可执行文件是git
,命令是commit
, -a
选项是传递给命令的选项。您可以使用 addCommand 方法添加命令:
var parser = ArgParser ();
var command = parser. addCommand ( 'commit' );
它返回另一个 ArgParser,然后您可以使用它来定义特定于该命令的选项。如果您已经有一个用于命令选项的 ArgParser,则可以将其传入:
var parser = ArgParser ();
var command = ArgParser ();
parser. addCommand ( 'commit' , command);
命令的 ArgParser 然后可以定义选项或标志:
command. addFlag ( 'all' , abbr : 'a' );
您可以将多个命令添加到同一个解析器,以便用户可以从一系列可能的命令中选择一个。解析参数列表时,您可以确定输入了哪个命令以及为其提供了哪些选项。
var results = parser. parse ([ 'commit' , '-a' ]);
print (results.command.name); // "commit"
print (results.command[ 'all' ]); // true
命令的选项必须出现在参数列表中的命令之后。例如,给定上述解析器, "git -a commit"
无效。解析器尝试找到最右边接受选项的命令。例如:
var parser = ArgParser ();
parser. addFlag ( 'all' , abbr : 'a' );
var command = parser. addCommand ( 'commit' );
command. addFlag ( 'all' , abbr : 'a' );
var results = parser. parse ([ 'commit' , '-a' ]);
print (results.command[ 'all' ]); // true
在这里,顶级解析器和"commit"
命令都可以接受"-a"
(诚然,这可能是一个糟糕的命令行界面)。在这种情况下,当"-a"
出现在"commit"
之后时,它将应用于该命令。如果它出现在"commit"
的左侧,则将其提供给顶级解析器。
如果您正在编写基于命令的应用程序,则可以使用 CommandRunner 和 Command 类来帮助构建它。 CommandRunner 内置支持根据命令行参数分派命令,以及处理--help
标志和无效参数。
使用 CommandRunner 时,它会替换 ArgParser。
在下面的示例中,我们构建了一个名为dgit
的 dart 应用程序,它接受命令commit
和stash
。
CommandRunner 采用executableName
名称,用于生成帮助消息。
例如dgit commit -a
文件dgit.dart
void main ( List < String > args) {
var runner = CommandRunner ( "dgit" , "A dart implementation of distributed version control." )
.. addCommand ( CommitCommand ())
.. addCommand ( StashCommand ())
.. run (args);
}
当上面的run(args)
行执行时,它会解析命令行 args 来查找命令之一( commit
或stash
)。
如果 CommandRunner 找到匹配的命令,则 CommandRunner 对匹配的命令调用重写的run()
方法(例如 CommitCommand().run)。
命令是通过扩展 Command 类来定义的。例如:
class CommitCommand extends Command {
// The [name] and [description] properties must be defined by every
// subclass.
final name = "commit" ;
final description = "Record changes to the repository." ;
CommitCommand () {
// we can add command specific arguments here.
// [argParser] is automatically created by the parent class.
argParser. addFlag ( 'all' , abbr : 'a' );
}
// [run] may also return a Future.
void run () {
// [argResults] is set before [run()] is called and contains the flags/options
// passed to this command.
print (argResults. flag ( 'all' ));
}
}
CommandRunner 允许您指定全局参数以及命令特定参数(甚至子命令特定参数)。
直接向 CommandRunner 添加参数以指定全局参数:
添加全局参数
var runner = CommandRunner ( 'dgit' , "A dart implementation of distributed version control." );
// add global flag
runner.argParser. addFlag ( 'verbose' , abbr : 'v' , help : 'increase logging' );
向每个命令添加参数以指定命令特定的参数。
CommitCommand () {
// we can add command specific arguments here.
// [argParser] is automatically created by the parent class.
argParser. addFlag ( 'all' , abbr : 'a' );
}
命令还可以有子命令,通过 addSubcommand 添加。带有子命令的命令不能运行自己的代码,因此不需要实现 run 。例如:
class StashCommand extends Command {
final String name = "stash" ;
final String description = "Stash changes in the working directory." ;
StashCommand () {
addSubcommand ( StashSaveCommand ());
addSubcommand ( StashListCommand ());
}
}
CommandRunner 自动添加一个help
命令,显示命令的使用信息,并支持所有命令的--help
标志。如果它在解析参数或处理命令时遇到错误,则会抛出UsageException;你的main()
方法应该捕获这些并适当地打印它们。例如:
runner. run (arguments). catchError ((error) {
if (error is ! UsageException ) throw error;
print (error);
exit ( 64 ); // Exit code 64 indicates a usage error.
});
您可以自动生成漂亮的帮助文本,适合用作--help
的输出。为了显示良好的使用信息,您应该在创建选项时提供一些帮助文本。
要定义整个选项的帮助文本,请使用help:
参数:
parser. addOption ( 'mode' , help : 'The compiler configuration' ,
allowed : [ 'debug' , 'release' ]);
parser. addFlag ( 'verbose' , help : 'Show additional diagnostic info' );
对于非标志选项,您还可以为参数提供帮助字符串:
parser. addOption ( 'out' , help : 'The output path' , valueHelp : 'path' ,
allowed : [ 'debug' , 'release' ]);
对于非标志选项,您还可以使用allowedHelp:
参数为每个期望值提供详细帮助:
parser. addOption ( 'arch' , help : 'The architecture to compile for' ,
allowedHelp : {
'ia32' : 'Intel x86' ,
'arm' : 'ARM Holding 32-bit chip'
});
要显示帮助,请使用用法 getter:
print (parser.usage);
结果字符串看起来像这样:
--mode The compiler configuration
[debug, release]
--out=<path> The output path
--[no-]verbose Show additional diagnostic info
--arch The architecture to compile for
[arm] ARM Holding 32-bit chip
[ia32] Intel x86