探究bash shell命令自动补全功能的实现方法——以xrandr为例分析

本文探讨了Linuxshell中xrandr命令的自动补全功能,揭示了bash-completion框架在其中的作用,以及开发者如何通过编写bash脚本实现动态和智能的补全,包括根据接口和实时信息提供选项。
摘要由CSDN通过智能技术生成

一直对shell的自动补全功能很感兴趣,趁此机会简单探究一下,一个成熟的应用程序究竟是怎么借助bash来完成自定义命令的补全的。

XrandR

简单介绍一下xrandr,它是一个命令行工具,用于管理和配置Linux系统中的显示器和屏幕分辨率。它是RandR(Resize and Rotate)扩展的一部分,该扩展允许动态调整显示器的分辨率、旋转方向和刷新率。
它的具体功能与本文内容无关,只要知道有这么一个工具就行了,可以自己在linux系统上随便敲几个xrandr的指令,感受一下它的自动补全功能。
xrandr自动补全
可以看到,xrandr既能对自定义的固定命令(如 --output)进行补全,又能根据随时变化的分辨率列表对分辨率信息进行补全。
它是如何实现这一功能的呢?

附一份xrandr的源码的链接
来自gitlab freedesktop的xrandr源码
如果不方便下载,我也会上传一份。

bash_completion

百度一下,可以知道,bash下的自动补全功能基本都是借助bash-completion完成的。

bash-completion是一个Bash补全功能的框架,它可以为Bash命令提供自动补全的功能。

但是网上给出的bash-completion讲解都比较简单,主要是针对
complete、compgen之类函数的功能的介绍。比如:
【shell】命令行自动补全(compgen、complete、compopt)
参照网上实例写出来的脚本固然可以实现自动补全,但是和成熟的应用程序比起来还差很远,尤其是xrandr这种根据前面输入的选项和实时信息提供补全的功能。

补全功能脚本示例

对于此类命令的补全功能,Linux提供了一个统一的路径用来存放它们的补全脚本。

/usr/share/bash-completion/completions/

程序在安装时,它的配套脚本就会被放入该路径。系统启动时,上一级目录有名为bash_completion的脚本,将completions/下的补全脚本会被加载,对应的补全函数即会生效。

在此路径下,我们可以找到名为"xrandr"的脚本,现在把它拆开来看一看。

# bash completion for xrandr                               -*- shell-script -*-

_xrandr()
{
    local cur prev words cword
    _init_completion || return

    case "$prev" in
        -display|-d|-help|-s|--size|-r|--rate|--refresh|--screen|--fb|--fbmm|\
        --dpi|--pos|--set|--scale|--transform|--crtc|--panning|--gamma|\
        --newmode|--rmmode|--addmode|--delmode)
            return
            ;;
        --output|--left-of|--right-of|--above|--below|--same-as)
            local outputs=$("$1" | awk '/connected/ {print $1}')
            COMPREPLY=( $(compgen -W "$outputs" -- "$cur") )
            return
            ;;
        --mode)
            local i output
            for (( i=1; i < cword; i++ )); do
                if [[ "${words[i]}" == --output ]]; then
                    output=${words[i+1]}
                    break
                fi
            done
            if [[ $output ]]; then
                local modes=$("$1" | command sed -e "1,/^$output / d" \
                    -e "/connected/,$ d" \
                    -e "s/\([^[:space:]]\)[[:space:]].*/\1/")
                COMPREPLY=( $(compgen -W "$modes" -- "$cur") )
            fi
            return
            ;;
        -o|--orientation)
            COMPREPLY=( $(compgen -W 'normal inverted left right 0 1 2 3' -- \
                "$cur") )
            return
            ;;
        --reflect)
            COMPREPLY=( $(compgen -W 'normal x y xy' -- "$cur") )
            return
            ;;
        --rotate)
            COMPREPLY=( $(compgen -W 'normal inverted left right' -- "$cur") )
            return
            ;;
        --setprovideroutputsource|--setprovideroffloadsink)
            local providers=$("$1" --listproviders 2>/dev/null |
                command sed -ne 's/.* name:\([^ ]*\).*/\1/p')
            COMPREPLY=( $(compgen -W "$providers" -- "$cur") )
            # TODO 2nd arg needed, is that a provider as well?
            return
            ;;
    esac

    COMPREPLY=( $(compgen -W '$("$1" -help 2>&1 |
        command sed -e "s/ or / /g" -e "s/<[^>]*>]//g" | _parse_help -)' \
        -- "$cur") )
} &&
complete -F _xrandr xrandr

# ex: filetype=sh

此脚本的case分支可以找到与xrandr功能对应的关键词,如–display、–pos、–rate等。
脚本末尾一行

complete -F _xrandr xrandr

使用complete -F指令,该指令告诉bash,当输入xrandr需要自动补全时,则调用_xrandr函数。至此,一个完成的自动补全功能就被搭建完成,要想使其有更灵活的补全功能,只需要在_xrandr函数中进行实现即可。

xrandr如何根据不同接口补全分辨率?

在实际使用中,不同的视频接口会有不同的分辨率列表。补全脚本又是如何根据用户的输入,提供对应的补全列表的呢?
我们可以看脚本中对于"–output"指令的补全,该选项的作用是给xrandr指定要配置的是哪一路显示输出,因此它应该提供当前所有的接口名,作为补全选项。

        --output|--left-of|--right-of|--above|--below|--same-as)
            local outputs=$("$1" | awk '/connected/ {print $1}')
            COMPREPLY=( $(compgen -W "$outputs" -- "$cur") )
            return
            ;;

这部分脚本很容易,只有两行。第一行是获取补全单词,把它们赋值给output变量;第二行是通用写法,调用compgen指令,把output变量里保存的单词当作补全选项提供给用户。
试着敲一下第一行这个命令看看输出:
脚本命令的执行结果,列出所有接口
再按照正常使用方法,敲一个–output选项然后按tab看看bash给出的补全选项:
按tab自动补全时,bash给出的选项
可以看到,二者给出的结果是一样的。

总结

至此,我们大概弄清楚了补全功能是怎么回事。总结一下一共是三点:

  • 使用bash提供的complete系列函数构建一个补全脚本来完成补全功能;
  • 将补全脚本放在/usr/share/bash-completion/completions/下,系统在启动时会自动加载;
  • 开发者主要的工作是实现补全函数,要运用各种bash指令对文本进行处理,进而达到“智能”的补全效果。
  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值