3
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

I have currently implemented a simple 'Did you mean..?' for plain English words which works as follow:

  • If user enters 'Kack', check the alphabets around every alphabet in the word on a QWERTY keyboard and substitute them one by one. (e.g. here they would be J,L,M,I,O for 'K'; Q,W,S,Z,X for 'a' and so on)
  • Return the word with the most probability (the user entered word itself too if that is the case) as the most likely word based on training on a corpus of text.

How is the code-suggestion implemented in the linux command line?

Ketcomp
  • 434
  • 6
  • 20

2 Answers2

5

bash does not implement the suggestion logic; it is in a function defined as part of your bash initialization file, and it was put there by your distribution (Ubuntu/Debian, at a guess).

bash provides the mechanism for implementating such a function: when it attempts to execute a command, and the command is not found, it invokes the function command_not_found_handle, if it is defined.

On my machine (an Ubuntu variant), that function is defined as follows:

$ 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
}

(And /usr/lib/command-not-found exists, is executable, and is a Python script.)

rici
  • 234,347
  • 28
  • 237
  • 341
  • Thanks! How did you know this? I mean in a more general way, say without SO, how would I have discovered what function is called from say, just the CLI? – Ketcomp Mar 01 '16 at 01:11
  • 1
    @Ketcomp: Read `man bash`. (It's in the third paragraph in the `COMMAND EXECUTION` section.) – rici Mar 01 '16 at 01:13
2

From the Bash man page:

COMMAND EXECUTION

[…]

If the name is neither a shell function nor a builtin, and contains no slashes, bash searches each element of the PATH for a directory containing an executable file by that name. Bash uses a hash table to remember the full pathnames of executable files (see hash under SHELL BUILTIN COMMANDS below). A full search of the directories in PATH is performed only if the command is not found in the hash table. If the search is unsuccessful, the shell searches for a defined shell function named command_not_found_handle. If that function exists, it is invoked with the original command and the original command's arguments as its arguments, and the function's exit status becomes the exit status of the shell. If that function is not defined, the shell prints an error message and returns an exit status of 127.

Let's try this out:

$ foobar
bash: foobar: command not found
$ function command_not_found_handle { echo "I'm so sorry, what is '$1'?"; }
$ foobar
I'm so sorry, what is 'foobar'?

Your shell initialization code might install a more useful command_not_found_handle. You would typically find such code in the system-wide configuration in /etc/bash.bashrc or a file sourced by it. Your distribution might install a handler there to invoke an external program that queries the distribution's package manager for the command or “similar” commands. For your Ubuntu, this would be implemented in the command-not-found package.

The default configuration files shipped by distributions are usually kept very general so the function might check whether the command-not-found binary is installed and, if so, call it or otherwise print a simple error message.

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
}

This way, the configuration file does not have to be changed if the command-not-found package is installed or removed again later.

I don't know how that program for Ubuntu is implemented but typically, such a tool would have a list of all known commands and find the most similar one. It might then check whether that program is installed and, if not, check what package provides it and suggest installing that.

Searching for “similar text” is usually done by computing the edit distance between two strings. Taking into account how likely mistyping a given letter is, given the current keyboard layout, would be a very smart addition.

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
  • After rici's answer, I was trying to use grep to find this relevant data in the man pages. But then you posted this ;) +1 for the in-line redefinition of the function to illustrate the logic better! – Ketcomp Mar 01 '16 at 01:25
  • 2
    @Ketcomp: In `man bash` (or in `man` anything), you can search by typing `/` followed by the string you want to search for, assuming that you are using `less` as your pager. `h` will give you a summary of the possible `less` commands. You'll find that easier than `grep`. – rici Mar 01 '16 at 01:31