在开发应用程序时,我开始纳闷-我应该如何设计命令行参数?

许多程序都使用类似-argument value/argument value这样的公式。我想到的解决方案是argument:value。我认为这是很好的,因为没有空格就无法将值和参数弄乱。同样很容易从左边的:字符的第一个字符串中将字符串拆分为两个。我的问题是: (更具可读性,更易于编写,无错误,更容易被专业开发人员理解)?
在设计命令行参数时,是否应该遵循一些众所周知的规则(如果可行,则可以使用)? />

我要求提供更多详细信息。但是我认为它们不应影响答案。问题是关于一般的良好习惯。我认为它们对所有类型的应用程序都是相同的。应用程序是使用Qt Quick 5(C ++,QML,JS)编写的。设备将安装Windows 8.1 / 10。我们将提供前端界面来管理设备。但是,某些高级管理员可能希望自己配置应用程序。从业务的角度来看这不是很重要,但是正如我同意Kilian Foth所说的那样,我不希望我的应用程序给用户带来麻烦。在Internet上找不到我要问的问题。


对于更高级的Stack Exchange用户:我希望这个问题笼统。也许它符合社区Wiki的资格(我不知道是否可以将现有问题转换为答案)。因为我希望这个问题与操作系统和编程语言无关,所以这里出现的答案对于其他开发人员可能是一个宝贵的教训。

评论

查看流行的命令行工具。例如,单个连字符通常用于允许组合选项。例如您可以编写ls -ltr组合选项-l,-t和-r。 GNU样式程序通常还允许使用带有双连字符的基于单词的选项,例如--reverse而不是-r。还有其他流行的约定,例如-h表示帮助,-表示选项结束,指定-作为文件名以允许从stdin读取等。

-argument value和-argument:value都不常见。常见的是-a值,-avalue和--argument = value。

尽可能使用流行的命令行解析库(通常称为getopt(s)之类的东西)。

@ k3b我们正在与Qt合作。正如kevin cline在他的评论中所说,我们可以使用已经可用的库。我认为它是多平台且经过深思熟虑的。 QCommandLineParser

最终的问题是参数解析不是平台无关的问题。

#1 楼

在POSIX系统(例如Linux,MacOSX)上,至少对于可能在Shell终端中启动的程序(例如其中的大多数),我建议使用GNU编码约定(还列出了常用的参数名称),并查看POSIX实用程序指南,甚至对于专有软件:


总是处理--version--help(甚至/bin/true也接受它们!)。我诅咒那些不了解--help的软件的作者,我讨厌他们(因为prog --help是我在新程序上尝试的第一个命令)!通常,--help可以缩写为-h
--help消息列表列出所有选项(除非您有太多的选项...在这种情况下,请列出最常见的选项并明确引用某些man页面或某些URL)和选项的默认值,以及可能重要的(和特定于程序的)环境变量。在选项参数错误时显示这些选项列表。
接受-a短参数(单字母)并具有等效的--long-argument,因此-a2 --long-argument=2--long-argument 2;当然,您可能会(对于很少使用的选项)使用一些--only-long-argument名称;对于没有额外选项的模态参数,通常将-cf处理为-c -f等,因此您的-argument:value提案很奇怪,因此我不建议这样做。 ...)
经常将Arg用于标准输入或输出(如果无法执行此操作,即使在少数几个没有它们的操作系统上也可以使用-/dev/stdin
通过模仿类似程序的行为重用其大多数选择约定;特别是/dev/stdout(用于空运行)(la -n),make(用于帮助),-h(用于详细说明)等。如果您的程序使用-v来测试stdin是否是终端(并且在这种情况下表现为“交互”),则提供一个选项来强制非交互模式,同样,如果您的程序具有GUI界面(并在X11桌面上测试--),也可以在批处理或命令行中使用。
某些程序(例如isatty)接受间接参数列表,因此getenv("DISPLAY")表示从gcc读取程序参数;当您的程序可能接受大量参数(而不是内核的@somefile.txt)时,这可能会很有用或somefile.txt

一些旧的Unix命令(例如ARG_MAX甚至bash)具有奇怪的命令参数以实现历史兼容性。我建议不要遵循它们的坏习惯(除非您对它们进行一些改进)。

如果您的软件是一系列相关的命令行程序,请从git中得到启发(您肯定会使用作为开发工具),它可以接受zshdd并具有许多sedgit help git --help git

在极少数情况下,您也可以使用subcommand(通过在程序上使用符号链接),例如作为git调用的subcommand具有不同的行为(受限制的shell)。但是我通常不建议这样做;如果可以使用shebang将您的程序用作脚本解释器,即execve(2)解释的第一行上的--help,则可能有意义。如果您使用了这些技巧,请确保将它们记录下来,包括在argv[0]消息中。

请记住,在POSIX上,shell会混淆参数(在运行程序之前!),因此请避免使用字符(例如bashrbash#!)中的选项,这些选项需要进行转义。

在某些情况下,您可以在软件中嵌入诸如GNU guile或Lua之类的解释器(如果您不是编程语言专家,请避免发明自己的图灵完整脚本语言)。这会对软件的设计产生深远的影响(因此应尽早考虑!)。然后,您应该可以轻松地将一些脚本或表达式传递给该解释器。如果您采用这种有趣的方法,请谨慎设计软件及其解释的原语;您可能会有一些奇怪的用户为您的事情编写大型脚本。 。同样,这是一个非常重要的设计决定(因此,请谨慎定义和记录插件接口),并且您需要定义一个约定,以将程序选项传递给这些插件。

如果您的软件是一件复杂的事情,使其接受一些配置文件(另外或替换程序参数),并且可能有某种方法可以测试(或只是解析)这些配置文件而无需运行所有代码。例如,邮件传输代理(例如Exim或Postfix)非常复杂,能够“半干”运行它(例如,观察它如何处理某些给定的电子邮件地址而不实际发送电子邮件)很有用。


请注意,--help是Windows或VMS。在POSIX系统上这太疯狂了(因为文件层次结构使用*作为目录分隔符,并且因为shell会进行globbing)。我所有的答案主要是针对Linux(和POSIX)的。


P.S.如果可能的话,使您的程序成为免费软件,您会从某些用户和开发人员那里得到改进(添加新程序选项通常是添加到现有免费软件中最容易的事情之一)。
另外,您的问题在很大程度上取决于目标受众:针对青少年的游戏或针对祖母的浏览器可能不需要与编译器,数据中心sysadmin的网络检查器或微处理器的CAD软件相同的选项和数量建筑师或桥梁设计师。熟悉编程和脚本的工程师可能比奶奶更喜欢具有很多可调选项,并且可能希望能够在没有X11的情况下运行您的应用程序(也许在$中工作)。

评论


同意,但是git是一个更好的例子。我什至不建议您在2016年浏览简历​​。

–Basile Starynkevitch
16 Jan 15'在10:01



+如果选项无效,请显示帮助。收到例如dd -h的无用错误消息实在令人讨厌。

–domen
16年1月15日在11:42

GNU程序通常支持--help,但通常不认识-h,这很烦人。当我忘记程序的选项时,通常会输入-h,但必须用更长的选项--help来重新输入命令是很烦的。毕竟,我键入-h是因为忘记了一些内容。为什么要让用户记住哪些程序需要“ --help”,哪些程序需要“ -h”以显示帮助屏幕?只需为-h和--help都包含一个选项即可。

–白兰地
16 Jan 15'在12:42



这个答案的第一部分是好的,但是沿着您的某个地方,切线会有些偏离。例如,配置文件,插件和dlopen,软件许可证的选择和Web浏览器不再与命令行界面的约定真正相关。

–白兰地
16 Jan 15 '13:58



拜托了如果确实要格式化屏幕输出,请添加输出格式替代。当我尝试在脚本中使用截断或换行的命令时,没有什么比让我感到烦恼的了。

–Sobrique
16年1月17日在12:52

#2 楼

数据格式约定很流行是它的优点。一点努力。对于人类来说,最大的努力就是记住“现在,这个不常用的程序是用:还是=来界定事物的?嗯……”天哪,没有令人信服的理由,请不要背离根深蒂固的惯例。人们会把您的程序记为“具有奇怪而烦人的cmdline语法的程序”,而不是“保存了我大学论文的程序”。

评论


对于几乎所有语言,都有库函数来处理命令行参数。使用其中之一。

–kevin cline
16年1月15日在8:43

好的建议,但是这些约定是什么? -1

–RubberDuck
16年1月15日在10:20

有一个有趣的常用UNIX工具示例,有意违反此约定:dd使用key = value语法。做出此设计决定的原因是,如果使用不当,此工具(昵称:数据破坏器)可能会造成很多损坏。通过强迫用户放弃他们的惯常习惯,他们迫使用户更加仔细地思考他们在做什么。

– Philipp
16 Jan 15'11:32



您确定这是dd的原因吗?我相信它只是在内核的ARG_MAX很小,外壳没有自动完成并且--long-arguments不存在的时候(1970年代?)编码的。从那时起,更好的dd保持向后兼容

–Basile Starynkevitch
16 Jan 15'11:43



dd起源于另一个OS(而不是UNIX)-IBM OS / 360上的脚本语言(JCL)-约定有所不同,在移植到UNIX之前或多或少保持不变-部分原因是那些可能使用它的人从以前的系统。

–巴德·科珀罗德(Baard Kopperud)
16年1月15日在12:47

#3 楼

用外行术语来说,在罗马时,请像罗马人那样做。 Linux有用于轻松解析此类参数和标志的工具。

我通常会执行以下操作: -p value


如果CLI应用程序适用于Windows,则请使用--parameter valuewhile [[ $# > 0 ]] do key="" case $key in --dummy) #this is a flag do something here ;; --audit_sessiones) #this is a flag do something here ;; --destination_path) # this is a key-value parameter # the value is always in , # you must shift to skip over for the next iteration path= shift ;; *) # unknown option ;; esac shift done 约定。 Oracle实用程序使用/flag
我想做的一件事是,除了在命令行中接受参数外,还提供使用parfile的选项,parfile是一个键值对文件,以避免冗长的参数链。为此,您应该提供一个附加的/flag:value参数。显然,如果使用PARAMETER=VALUE,则所有其他参数都将被丢弃,而转而使用parfile中的内容。 --parfile mifile.par
在Linux中,不要忘记添加参数自动完成功能,这意味着用户可以键入半个开关,然后按--parfile,然后Shell会为他们完成该操作。


评论


好吧,几个GNU实用程序(例如gcc)像--parfile mifile.par建议一样处理@ mifile.par。

–Basile Starynkevitch
16年1月15日在12:04

如果确定有参数文件,您确定要忽略所有其他选项吗?充其量听起来对我而言是违反直觉的。

–乔纳森·莱弗勒(Jonathan Leffler)
16年1月15日在14:56

我同意乔纳森(Jonathan)关于参数文件的意见。如果存在参数文件,那么我希望它可以用作默认值,并且命令行上给出的参数应放在parfile中。如果由于某种原因使用了parfile而不使用其他命令行参数,则附加参数的存在应该是错误的。

– Eldritch奶酪
16年1月15日在23:12

@EldritchCheese在我编写的CLI应用程序中,给定parfile时,任何附加参数都会产生错误。

–图兰斯·科尔多瓦(TulainsCórdova)
16年1月16日,0:04

如果使用有能力的外壳,则不需要这种“配置文件参数”选项。例如您只需编写fooCmd -opt1 -opt2 $(cat more_options.opts)。因此,我希望“配置文件参数”选项(如果提供)应该基本上以相同的方式工作。

–白兰地
16年1月16日在6:50

#4 楼

尚未出现的一件事:

尝试从命令行参数开始向上设计软件。
含义:

在设计功能之前,请先进行设计用户界面。

这将使您能够尽早深入研究边缘情况和常见情况。比仅编写所有代码然后再敲击CLI更好的结果。

此外,请查看docopt(http://docopt.org/)。

docopt在许多语言中都提供了很大的帮助,尤其是对于python而言,它的使用受到严重限制,像argparse这样的用户不利参数解析器仍然被认为是“确定”。定义语法帮助,其余的工作就会完成。

评论


我喜欢这个答案,并感谢您的回答,因为我目前对argparse既不是程序员,用户界面也不是用户友好感到沮丧。

–猫
16年1月15日在22:14

我尝试了docopt,但我不喜欢它。 click产生的代码更加简洁,尽管在使用子命令时选项有些不明确。

– jpmc26
16 Jan 15'23:03



这太像广告了。只需提及一次资源(如果相关)。但是就目前而言,您答案的50%听起来像是在推广外部资源。

–白兰地
16年1月16日在6:52

我将其表述为“首先设计使用模型”。在许多情况下,将用户体验与功能区分开可能是人为的区分(工具限制会影响界面)。

–copper.hat
16年1月16日在18:41

Docopt +1。它解决了我所有的CLI难题,完全没有痛苦。有时很难从真正的热情中分辨出广告,但是在这里-我多年来一直是Docopt的狂热者,没有任何联系;

–frnhr
16年1月21日在21:41

#5 楼

已经提供了一些有价值的评论(@ Florian,Basile),但让我添加一下...但是,一些高级管理员可能希望自己配置应用程序


但也要注意以下几点:


我不想将此问题作为平台或特定于语言的内容


您必须考虑目标受众-高级管理员。他们通常在什么平台上工作-Win / Unix / Mac?您的应用在什么平台上运行?遵循已为该平台建立的任何CLI约定。您的“高级”管理员是否想要/需要基于GUI的工具?

您希望界面在内部以及与其他管理员工具保持一致。我不想停下来思考这是cmd -p <arg>还是cmd -p:<arg>cmd /p <arg>。我需要引号'cos那里有空格吗?我可以将cmd -p <val1> <val2>cmd -p <val1> -p <val2>用于多个目标吗?它们是特定于订单的吗?可重载吗? cmd -p2 <arg> -p1 <arg>也可以吗? ls -l -r -t dir1 dir2 == ls -trl dir1 dir2吗?

对于我的Unix管理工具,我始终牢记Heiner的Shelldorado提供的指南以及所提到的其他参考文献。确保您的应用程序设计为使用与GUI中相同的命令行参数-即:GUI中没有业务逻辑,或使用从GUI和CLI调用的通用命令。

大多数基于UNIX的管理工具实际上都是首先设计为命令行工具的,而提供的GUI只是简化了“填充”命令行选项的工作。这种方法可以实现自动化,响应文件的使用等,还可以进行自动管理(对我而言,工作量更少!)

作为使用此方法的经典工具集,它是Tcl / Tk。不建议您切换工具;只需考虑以下设计方法:首先将基于GUI的管理应用程序编写为命令行工具即可;然后为方便起见将GUI放在最上面。在某些时候,如果您必须进行多个配置并一遍又一遍地重新输入相同的选项,并且可能会发现GUI是一种痛苦(并且容易出错),并且您会寻找一种自动化的方法。

请记住,无论如何,您的管理员很可能必须在正确的框中键入正确的值,所以您需要付出多少努力才能使用GUI?

评论


太好了!一个问题是:我可以运行./this-script --hosts
–弗洛里安·海格尔(Florian Heigl)
16 Jan 19 '23:43