背景 链接到标题

关于实现命令行的一点总结。

有用的帮助信息 链接到标题

提供的命令行中所有的命令、子命令、选项都有明确的帮助信息,便于用户在使用过程中查看。帮助信息查看方式最好统一,比如统一使用 -h 格式、 COMMAND help 或者 COMMAND --help

尽量使用 Flags 而不是 Args 链接到标题

命令行可以接受 2 种类型的参数输入:Flags 和 Args。Flags 需要更多的输入,但会使命令行更清晰。我在实现一个命令行时,通常会将必选项设置为 Args ,将可选项设置为 Flags,但是有时候会导致用户在使用过程中觉得传递参数方式不统一,而且当 Args 有多个时(是的,我之前设计的一个命令行输入的 Args 多达 5 个)用户敲着敲着就不知道自己该输入什么了。如果在后续对命令行进行重构时,为了保证接口的兼容性,Args 通常是需要保证不变的,而 Flags 没有这个困扰。在使用 Flags 时,如果 Flags 是必要参数,要将其标记为 Required。

环境变量 链接到标题

如果可以的话,建议将命令行参数设置为可以接受环境变量的形式,容器化运行、用户要重复执行时,都会很方便。在设置环境变量时,尽量避开 $USER/$USERNAME 通用变量,建议增加对应命令前缀,如 VM_USERNAME

输入校验 链接到标题

无论是通过 Args、Flags 还是环境变量来获取输入参数,都建议对参数进行完整的校验,并给出友好提示。

交互式命令 链接到标题

有时在编写业务代码时,为了避免用户执行出错,所以会有二次确认的提示,比如 [Yes/No] 或者二次输入某些信息,在日常使用中可能会避免一些问题,但是如果后续要代码封装的话,就会让调用者较为痛苦。建议在存在交互式的命令中,添加参数可以跳过交互,或者提前指定,比如 --force

明确显示当前版本 链接到标题

在使用过程中,如果遇到了问题,那么通常需要上报命令行版本反馈,需要明确给出当前命令行所指定的版本。通常会有 -v, -V, --version, version 等子命令,其中 -v-V 有可能会跟 verbose 混淆,建议将版本作为一个独立的子命令 version 来实现。

针对 stdint, stdout, stderr 正确使用 链接到标题

如果已知一个命令行的执行耗时较长,那么用户通常执行命令时会选择将 stdout 重定向到指定文件中,便于后续查看执行过程输出,留存。但是如果在执行过程中出现异常,那么尽量将异常信息通过 stderr 输出,及时暴露给用户。默认情况下 stdout 被重定向之后,stderr 仍会打印在终端中。

当命令本身预期输出是一个结构化的数据(json/yaml),命令同时还支持配置 LOG_LEVEL,那么当 LOG_LEVEL 设置为 DEBUG 时,可以考虑将 LOG 输出到 stderr,保证 stdout 始终是预期输出,可以避免对其他使用者解析命令输出造成困扰。

明确的错误信息 链接到标题

当用户在执行命令过程中遇到错误,需要尽可能的显示多的、有用的信息出来:错误码、错误描述、错误信息。给出的信息是人类友好的,毕竟针对错误进行调试的是我们自己。尽量保证自己的命令行提供调试模式(类似于 Shell 中的 set -x ),便于 debug。

可以参考 Google 的 Writing Helpful Error Messages

不要过分花里胡哨 链接到标题

现在许多命令行会在执行过程中,为了保证自己的输出尽可能的“好看”,可能会做各种丧心病狂的事情(比如塞入 emoji),我建议尽量不要做这种事情,会带来很多心智负担。

(如果可能的话)不要输出表格 链接到标题

有时候命令执行结果返回中,包含的信息量很大,那么通常会使用各种 table lib 来“友好”的展示信息。这类信息可能会导致在后续进行二次处理(sed, awk)过程中增加工作量,需要额外的过滤表格中的字符。如果一定需要展,那么尽可能提供可选项,给出一个其他的输出格式,比如 json,比如 yaml 等等。

保证执行速度 链接到标题

尽量保证命令行执行耗时较短,如果耗时较长,那么可能遇到的网络问题导致命令执行中断的概率增加。在执行过程中,尽量让用户感受到命令是在执行的,给出明确的交互状态,不要让用户感觉命令 hang 住。

处理好信号 链接到标题

当用户在执行一个命令的时候,保证用户可以最终停止它。在处理信号的过程中,可以合理的输出一些有用的提示告知用户当前正在进行什么动作。

幂等 链接到标题

尽量保证命令行幂等,当命令执行失败之后,可以让用户再次执行该命令以完成最终目的,否则会相当痛苦。

参考链接 链接到标题