命令行自动补全原理

简介:

概述

虽然CLI(命令行)类型的工具由于其高效,易定制的特性为很多人所喜爱(也包括我自己), 但是,相对于GUI工具,CLI工具给人的直观感觉就是不容易使用,如果看到工具中大量的参数说明后,更让人望而却步。

因此,如果在自己命令行工具中加入 自动补全 的功能,就可以极大的提高工具的易用性,还可以保留命令行工具原有的高效。 这里所说的 自动补全 不仅仅是补全那些固定的参数(这些意义不大),更多的是补全动态的内容。

本篇主要介绍两种主流的 shell(bash 和 zsh)中,如何实现命令行工具的补全。

bash 自动补全

测试补全的脚本

简单编写一个测试脚本用来测试后面的自动补全:

#!/bin/bash
# filename: cli-test.sh

UPCASE=false
DATE=""

usage() {
    echo "USAGE:"
    echo "cli-test <options>"
    echo "    -h      : print help"
    echo "    -u      : print info upcase"
    echo "    -p <xxx>: print info"
    echo "    -d <xxx>: date in print info"
}

print() {
    if $UPCASE
    then
       echo -n $1 | tr a-z A-Z
    else
        echo -n $1
    fi

    if [ "$DATE" != "" ]
    then
        echo "   date: $DATE"
    else
        echo ""
    fi
}

while getopts "hup:d:" opt; do
    case "$opt" in
        h)
            usage
            exit 0
            ;;
        u)
            UPCASE=true
            ;;
        d)
            DATE=$OPTARG
            ;;
        p)
            print $OPTARG
            ;;
    esac
done

测试上面的脚本如下:

bash-3.2$ chmod +x cli-test.sh
bash-3.2$ ./cli-test.sh -h
USAGE:
cli-test <options>
    -h      : print help
    -u      : print info upcase
    -p <xxx>: print info
    -d <xxx>: date in print info
bash-3.2$ ./cli-test.sh -p hello
hellobash-3.2$ ./cli-test.sh -p hello
hello
bash-3.2$ ./cli-test.sh -u -p hello
HELLO
bash-3.2$ ./cli-test.sh -u -d 2016-10-13 -p hello
HELLO   date: 2016-10-13

参数自动补全

参数的补全一般来说比较简单,因为一个命令行工具的参数一般都是固定的。 下面的参数补全脚本是针对 上面的 测试补全的脚本 cli-test.sh

_complete_func() {
    local cur prev opts base
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    opts="-h -u -d -p"

    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi

}

complete -F _complete_func cli-test.sh

让自动补全脚本生效的方法如下:

bash-3.2$ source bash_complete          # 使自动补全脚本生效
bash-3.2$ ./cli-test.sh -<TAB><TAB>     # 这里输入 - 之后,再输入2次<TAB>就可以把所有能补全的参数列出来

自定义补全

上面的补全是补全固定的参数,简单,但是用处也不大,用户记不住的其实就是那些会变的参数内容。 下面尝试动态补全 cli-test.sh 的参数 -d 的内容(内容是当前日期以及前3天和后三天的日期) 修改 bash_complete 脚本如下:

_complete_func() {
    local cur prev opts base
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    if [[ ${cur} == -* ]] ; then
        opts="-h -u -d -p"
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
    else
        opts=$( _complete_d_option )
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
    fi

    return 0
}

_complete_d_option() {
    date -v -3d +"%Y-%m-%d"
    date -v -2d +"%Y-%m-%d"
    date -v -1d +"%Y-%m-%d"
    date +"%Y-%m-%d"
    date -v +1d +"%Y-%m-%d"
    date -v +2d +"%Y-%m-%d"
    date -v +3d +"%Y-%m-%d"
}

complete -F _complete_func cli-test.sh

测试动态补全的效果

bash-3.2$ source bash_complete          # 使自动补全脚本生效
bash-3.2$ ./cli-test.sh -u -d 2016-10-1<TAB><TAB>   # 这是 2016-10-13 执行的结果,其他日子的结果会不一样
2016-10-10  2016-10-11  2016-10-12  2016-10-13  2016-10-14  2016-10-15  2016-10-16

上面就是动态补全,_complete_d_option 函数就是用来实现动态补全的。

zsh 自动补全

相比于bash,zsh 的补全机制更加强大,也更加直观。 同样,下面也通过例子来演示如何在 zsh 中实现上面 bash 中同样的补全功能。

参数自动补全

相比于 bash 的自动补全脚本,我觉得 zsh 的补全方式更加直观。

#compdef cli-test.sh
# filename: _cli-test.h

_cli_test() {

    _arguments -C -s -S \
               '-h::' \
               '-u::' \
               '-d::' \
               '-p::'
}

_cli_test "$@"

zsh 中有个 fpath 的内置变量,将自动补全脚本放在 $fpath 中,或者在 $fpath 中创建指向自动补全的脚本的软连接都可以。 下面是我的环境中 fpath 的值

$ echo $fpath
/usr/local/share/zsh/site-functions /usr/share/zsh/site-functions /usr/share/zsh/5.0.8/functions

为了测试 zsh 下自动补全是否有效,我在 fpath 下给自己的自动补全脚本创建了软连接

$ cd /usr/local/share/zsh/site-functions
$ ln -s ~/projects/bash/autocomp/_cli-test.sh _cli-test.sh

测试结果

$ ./cli-test.sh -<TAB><TAB>
-d  -h  -p  -u

可以看出,zsh 的补全方法非常简单直观。稍微解释下上面的代码

_arguments

这个函数是 zsh 自带的,有点类似 bash 中的 compgen ,但是功能更加强大。

'-h::' \

这里 : 分割的3部分分别是 “待补全的参数:参数的说明:动态补全参数的内容“

自定义补全

根据上面的解释,要想动态补全 -d 参数非常简单,只要加个函数,并配置在 -d:: 之后即可

#compdef cli-test.sh
# filename: _cli-test.h

_cli_test() {

    _arguments -C -s -S \
               '-h::' \
               '-u::' \
               '-d:auto complete date:__complete_d_option' \
               '-p::'
}

__complete_d_option() {
    local expl
    dates=( `generate_date` )

    _wanted dates expl date compadd $* - $dates
}

generate_date() {
    date -v -3d +"%Y-%m-%d"
    date -v -2d +"%Y-%m-%d"
    date -v -1d +"%Y-%m-%d"
    date +"%Y-%m-%d"
    date -v +1d +"%Y-%m-%d"
    date -v +2d +"%Y-%m-%d"
    date -v +3d +"%Y-%m-%d"
}

_cli_test "$@"

测试动态补全的效果

$ ./cli-test.sh -u -d 2016-10-<TAB><TAB>
2016-10-14  2016-10-15  2016-10-16  2016-10-17  2016-10-18  2016-10-19  2016-10-20

总结

2中shell环境下的自动补全都介绍完了,它们自动补全的机制都不难,只是 zsh 毕竟是新一点的shell,补全方式更加简单易懂。 特别是对于存在子命令和复杂的参数补全,以及参数内容动态补全的情况下,zsh 的机制更加易于维护。

来源:http://blog.iotalabs.io/



本文转自wang_yb博客园博客,原文链接:http://www.cnblogs.com/wang_yb/p/5969451.html,如需转载请自行联系原作者


目录
相关文章
|
Java 程序员 API
Java并发基础:concurrent Flow API全面解析
java.util.concurrent.Flow定义了响应式编程的核心接口,促进了Java在异步数据处理和背压机制方面的标准化,这使得第三方库如Reactor和RxJava能够基于这些接口提供丰富的实现和功能,同时简化了响应式编程在Java中的使用,Flow API增强了Java在并发编程领域的灵活性,使得处理异步数据流变得更加自然和高效。
1144 0
Java并发基础:concurrent Flow API全面解析
|
SQL NoSQL Java
JAVA使用Apcahe Calcite 解析sql
JAVA使用Apcahe Calcite 解析sql
4701 0
|
数据处理 计算机视觉 Python
【目标检测】指定划分COCO数据集训练(车类,行人类,狗类...)
【目标检测】指定划分COCO数据集训练(车类,行人类,狗类...)
6426 0
|
7月前
|
传感器 人工智能 安全
Claude 开始进桌面之后,AI 系统的测试边界是不是又变了?
AI正从“问答工具”跃升为“操作执行者”,深度融入桌面、办公与企业系统。对测试而言,边界已从结果验证扩展至过程、环境、风险与长期稳定性验证——传统功能测试失效,亟需构建覆盖任务链路、异常恢复、安全可控的AI专属测试框架。
|
8月前
|
人工智能 自然语言处理 API
Cline的部署以及免费API集成教学
Cline是VS Code内置AI编程助手,支持自然语言指令理解、代码导航修改、终端执行、调试与迭代开发。需安装扩展并配置CanopyWave等兼容OpenAI的API密钥(如Kimi/Qwen/GLM模型),一键完成端到端软件开发。
1836 6
|
人工智能 前端开发 机器人
10+热门 AI Agent 框架深度解析:谁更适合你的项目?
一个合适的 Agent 框架,决定了你AI应用落地的速度与质量。选框架 ≠ 选最火! 真正能跑起来、跑得稳、跑得远的 Agent 框架,才是你的最优解。
|
人工智能 自然语言处理 运维
AI agent跨平台云资源智能管理终端是什么
随着多云架构和混合IT环境的普及,企业面临跨平台资源协同效率低、操作复杂等问题。为此,跨平台云资源智能管理终端应运而生。它通过模块化架构与自动化引擎,将异构云环境中的资源统一管理,并提供对话式交互、批量操作与智能策略编排能力。典型产品如Chaterm,支持自然语言指令输入,实现从任务规划到执行反馈的闭环体验。其应用场景涵盖大规模服务器集群管理、跨云资源调度、复杂环境自动化配置等,显著提升效率与可靠性。实施时需关注兼容性、扩展性及安全性,建议从试点入手逐步推广,优化企业运维流程。
765 5
|
Linux Go iOS开发
Go语言新手指南:正确使用GOPATH的步骤
Go语言新手指南:正确使用GOPATH的步骤
7166 0
|
前端开发 Linux 程序员
成功解决:如何修改CentOS 7中终端背景色和字体颜色
这篇文章介绍了如何在CentOS 7中修改终端的背景色和字体颜色。文章提供了修改步骤,包括打开终端、选择配置文件首选项、取消默认颜色设置并自定义颜色,以及修改后的效果展示。作者表达了对默认白色主题的不习惯,并鼓励读者学习无止境。
成功解决:如何修改CentOS 7中终端背景色和字体颜色
|
Ubuntu Linux 编译器
Linux Ubuntu命令行快速配置C++开发环境
Linux Ubuntu命令行快速配置C++开发环境
839 1