命令建议是如何在 bash shell 中实现的?

Posted

技术标签:

【中文标题】命令建议是如何在 bash shell 中实现的?【英文标题】:How is the command suggestion implemented in the bash shell? 【发布时间】:2016-06-13 06:26:33 【问题描述】:
gk@Jarvis:~$ sudi
No command 'sudi' found, did you mean:
Command 'sudo' from package 'sudo-ldap' (universe)
Command 'sudo' from package 'sudo' (main)
sudi: command not found

我目前已经实现了一个简单的“你的意思是......?”对于简单的英语单词,其工作方式如下:

如果用户输入“Kack”,请在 QWERTY 键盘上检查单词中每个字母周围的字母并逐一替换。 (例如,在这里它们将是 J、L、M、I、O 代表“K”;Q、W、S、Z、X 代表“a”等等) 根据对文本语料库的训练,返回最有可能的词(如果是这种情况,用户也输入了词本身)作为最有可能的词。

linux命令行中的代码建议是如何实现的?

【问题讨论】:

【参考方案1】:

bash 没有实现建议逻辑;它位于一个定义为 bash 初始化文件的一部分的函数中,并且它是由您的发行版(Ubuntu/Debian,猜测)放在那里的。

bash 提供了实现这样一个功能的机制:当它试图执行一个命令,但没有找到该命令时,它调用函数command_not_found_handle,如果它被定义了。

在我的机器(一个 Ubuntu 变体)上,该函数定义如下:

$ type command_not_found_handle
command_not_found_handle is a function
command_not_found_handle () 
 
    if [ -x /usr/lib/command-not-found ]; then
        /usr/lib/command-not-found -- "$1";
        return $?;
    else
        if [ -x /usr/share/command-not-found/command-not-found ]; then
            /usr/share/command-not-found/command-not-found -- "$1";
            return $?;
        else
            printf "%s: command not found\n" "$1" 1>&2;
            return 127;
        fi;
    fi

(并且/usr/lib/command-not-found 存在,可执行,并且是 Python 脚本。)

【讨论】:

谢谢!你是怎么知道的?我的意思是更一般地说,如果没有 SO,我怎么会发现从 CLI 中调用的函数? @Ketcomp:阅读man bash。 (在COMMAND EXECUTION 部分的第三段中。)【参考方案2】:

来自 Bash 手册页:

命令执行

[…]

如果名称既不是 shell 函数也不是内置函数,并且不包含斜杠,bash 会在 PATH 的每个元素中搜索包含该名称的可执行文件的目录。 Bash 使用哈希表来记住可执行文件的完整路径名(请参阅下面的 SHELL BUILTIN COMMANDS 下的hash)。仅当在哈希表中找不到该命令时,才会对 PATH 中的目录进行完整搜索。如果搜索不成功,shell 将搜索一个已定义的名为 command_not_found_handle 的 shell 函数。如果该函数存在,则使用原始命令和原始命令的参数作为其参数调用它,并且该函数的退出状态变为 shell 的退出状态。如果未定义该函数,shell 会打印一条错误消息并返回退出状态 127。

让我们试试这个:

$ foobar bash:foobar:找不到命令 $ function command_not_found_handle echo "我很抱歉,'$1' 是什么?"; $ foobar 对不起,什么是'foobar'?

您的 shell 初始化代码可能会安装一个更有用的command_not_found_handle。您通常会在/etc/bash.bashrc 的系统范围配置中找到此类代码,或者从它获取的文件中找到此类代码。您的发行版可能会在那里安装一个处理程序来调用一个外部程序,该程序会向发行版的包管理器查询命令或“类似”命令。对于您的 Ubuntu,这将在 command-not-found package 中实现。

发行版提供的默认配置文件通常非常通用,因此该函数可能会检查是否安装了 command-not-found 二进制文件,如果是,则调用它或打印简单的错误消息。

function command_not_found_handle 
    if [ -x /usr/bin/command-not-found ]
    then
        /usr/bin/command-not-found "$1"
    else
        echo "$1: Command not found" >&2
        return 127
    fi

这样,以后再次安装或删除command-not-found包时,无需更改配置文件。

我不知道 Ubuntu 的程序是如何实现的,但通常,这样的工具会列出所有已知命令并找到最相似的命令。然后它可能会检查该程序是否已安装,如果没有,则检查提供它的软件包并建议安装。

搜索“相似文本”通常是通过计算两个字符串之间的edit distance 来完成的。考虑到给定字母的错误输入可能性,考虑到当前的键盘布局,这将是一个非常明智的补充。

【讨论】:

在 rici 的回答之后,我尝试使用 grep 在手册页中查找这些相关数据。但是后来你发布了这个;) +1 用于函数的内联重新定义以更好地说明逻辑!​​ @Ketcomp:在man bash(或man 任何内容)中,您可以通过键入/ 后跟要搜索的字符串进行搜索,假设您使用的是less作为您的寻呼机。 h 将为您提供可能的less 命令的摘要。你会发现这比grep 更容易。

以上是关于命令建议是如何在 bash shell 中实现的?的主要内容,如果未能解决你的问题,请参考以下文章

Linux如何获取命令帮助

如何在bash shell中执行for循环生成的curl命令?

如何在 Python 中实现常见的 bash 习语? [关闭]

如何列出所有的 Bash Shell 内置命令 | Linux 中国

有限自动机是如何在代码中实现的?

linux基础:shell中的sh与bash区别与常用命令