Go语言打造高效命令行神器

github.com/chzyer/readline 是一个采用纯 Go 语言开发的交互式命令行库,它完整实现了类似 GNU Readline 的功能特性,并具备跨平台终端操作能力。

一、核心功能

1)多平台支持

采用分平台文件实现(如 term_linux.go、term_windows.go),可跨平台支持终端原始模式控制,兼容 Linux/BSD/Windows 系统。

2)行编辑能力

支持 Emacs/Vi 风格的快捷键操作(例如 Ctrl+A 快速跳转至行首)。

内置 runebuf.go 模块实现高效的符文缓冲区管理,全面兼容 Unicode 字符输入。

3)自动补全系统

内置complete.go 实现了层级补全树功能,支持静态预定义补全和动态生成补全两种补全方式。

4)支持历史命令

按上下方向键可快速查看和切换历史输入命令。

二、关键组件

模块文件功能描述实现要点
operation.go处理用户输入操作封装 Ctrl+C 等中断信号
history.go命令历史管理支持持久化到文件
password.go安全密码输入屏蔽回显并自定义提示
search.go历史命令搜索支持增量搜索匹配

三、realine基本用法

编写一个简单交互式命令行,支持ip和iptables命令补全功能,默认支持按上下方向键切换历史输入命令。代码示例如下:

package main

import (
    "fmt"
    "github.com/chzyer/readline"
)

func main() {

    // 内置补全命令,安tab键补全
    var completer = readline.NewPrefixCompleter(

        // 补全命令ip,支持ip addr 和 ip link两种命令
        readline.PcItem("ip",
            readline.PcItem("addr"),
            readline.PcItem("link"),
        ),

        // 补全命令iptables,支持iptables stop 和 iptables start两种命令
        readline.PcItem("iptables",
            readline.PcItem("stop"),
            readline.PcItem("start"),
        ),
    )

    rl, err := readline.NewEx(&readline.Config{
        InterruptPrompt: "^C", // 支持ctrl + c关闭命令行
        AutoComplete:    completer, // 设置补充命令
    })

    if err != nil {
        fmt.Println("err:", err)
        return
    }

    defer rl.Close()

    // 交互循环
    for {

        rl.SetPrompt("输入 > ")

        // 接收数据
        line, err := rl.Readline()
        if err != nil {
            break
        }

        println("   接收:", line)
    }
}

运行之后,直接按tab键,会显示ip和iptables提示,如下所示:

当选择ip命令后,继续按tab键,会显示ip之后可加的addr和link提示,如下所示:

可通过HistoryFile将历史命令进行文件存储,结合HistoryLimit限制历史命令存储个数,代码示例如下:

rl, err := readline.NewEx(&readline.Config{
    InterruptPrompt: "^C",      // 支持ctrl + c关闭命令行
    AutoComplete:    completer, // 设置补充命令
    HistoryFile: "/tmp/.app_history", // 历史命令存储文件
    HistoryLimit: 1000,  // 限制1000条历史
})

四、高级特性

1)动态补全实现

通过回调函数实时生成补全项(如文件系统补全),代码示例如下:

func listFiles() []readline.PrefixCompleterInterface {
    files, _ := os.ReadDir(".")
    var items []readline.PrefixCompleterInterface
    for _, f := range files {
        items = append(items, readline.PcItem(f.Name()))
    }
    return items
}

func main() {


    // 配置补全器时注入动态生成函数
    completer = readline.NewPrefixCompleter(
        readline.PcItem("ls", listFiles()...),
    )

    rl, err := readline.NewEx(&readline.Config{
        InterruptPrompt: "^C",                // 支持ctrl + c关闭命令行
        AutoComplete:    completer,           // 设置补充命令
        HistoryFile:     "/tmp/.app_history", // 历史命令存储文件
        HistoryLimit:    1000,                // 限制1000条历史
    })

    if err != nil {
        fmt.Println("err:", err)
        return
    }

    defer rl.Close()

    // 交互循环
    for {

        rl.SetPrompt("输入 > ")

        // 接收数据
        line, err := rl.Readline()
        if err != nil {
            break
        }

        println("   接收:", line)
    }
}

执行结果如下:

2)多模式切换

实现了vi和emacs两种编辑模式的切换,支持 Emacs/Vi 风格的快捷键操作,通过调用SetVimMode()函数切换输入模式,并利用监听器实时更新提示符显示。代码示例如下:

func main() {

    rl, err := readline.NewEx(&readline.Config{
        InterruptPrompt: "^C",      // 支持ctrl + c关闭命令行
    })

    if err != nil {
        fmt.Println("err:", err)
        return
    }

    defer rl.Close()

    // 交互循环
    for {

        rl.SetPrompt("输入 > ")

        // 接收数据
        line, err := rl.Readline()
        if err != nil {
            break
        }

        if strings.HasPrefix(line, "mode ") {
            switch line[5:] {
            case "vi":
                rl.SetVimMode(true)
            case "emacs":
                rl.SetVimMode(false)
            }
        }

        println("   接收:", line)
    }
}

3)安全密码输入

readline库提供了专门的密码输入功能,支持自定义密码输入时的提示和显示。代码示例如下:

func main() {

    rl, err := readline.NewEx(&readline.Config{
        InterruptPrompt: "^C", // 支持ctrl + c关闭命令行
    })

    if err != nil {
        fmt.Println("err:", err)
        return
    }

    defer rl.Close()

    setPasswordCfg := rl.GenPasswordConfig()
    setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
        rl.SetPrompt(fmt.Sprintf("输入密码(%v): ", len(line)))
        rl.Refresh()
        return nil, 0, false
    })

    // 交互循环
    for {

        // 接收数据
        line, err := rl.ReadPasswordWithConfig(setPasswordCfg)
        if err != nil {
            break
        }

        fmt.Printf("密码:%s", line)
    }
}

能够实施显示输入的密码长度,执行结果如下:

4)彩色输出渲染

通过ANSI代码实现终端着色,代码示例如下:

func main() {

    rl, err := readline.NewEx(&readline.Config{
        InterruptPrompt: "^C", // 支持ctrl + c关闭命令行
    })

    if err != nil {
        fmt.Println("err:", err)
        return
    }

    defer rl.Close()

    rl.Write([]byte("\033[31m红色错误信息\033[0m\n"))
    rl.SetPrompt("\033[32m绿色提示 > \033[0m")

    // 交互循环
    for {

        // 接收数据
        line, err := rl.Readline()
        if err != nil {
            break
        }

        fmt.Printf("  输入:%s\n", line)
    }
}

执行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值