> ## Content Index
> Fetch the complete content index at: https://www.sfeir.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Gérez les commandes introuvables dans le shell
- URL: https://www.sfeir.dev/front/commandes-introuvables-pas-de-panique/
- Published: 2023-06-16T10:45:00.000Z
- Updated: 2023-11-02T11:29:49.000Z
- Description: Personnalisons la gestion des erreurs de commandes introuvables pour agrémenter l'expérience développeur.
- Author: Alexandre Moevi
- Tags: Back, Front, Tips

Si vous avez déjà travaillé dans un environnement de type Unix, vous avez sans doute remarqué cette erreur quand vous tentiez d'exécuter une commande inexistante.

```zsh
$ cqt output.txt
zsh: command not found: cqt
```

Que se passe-t-il sous le capot ? Le manuel Linux nous l'explique.

> ... Si la recherche est infructueuse, l'interpréteur de commandes recherche une fonction définie de l'interpréteur de commandes nommée `**command_not_found_handle**`.   
>  
> Si cette fonction existe, elle est invoquée dans un environnement d'exécution distinct avec la commande d'origine et les arguments de la commande d'origine comme arguments, et l'état de sortie de la fonction devient l'état de sortie de ce sous-shell.  
>  
> Si cette fonction n'est pas définie, l'interpréteur de commandes affiche un message d'erreur et renvoie un état de sortie de 127.  
>  
> ([Extrait traduit du manuel Linux](https://www.man7.org/linux/man-pages/man1/bash.1.html?ref=sfeir.dev#:~:text=If%20the%20search%20is,exit%20status%20of%20127.))

Dans notre cas, nous n'avons pas (encore) défini la fonction `command_not_found_handle`, donc un message d'erreur est affiché et le code de sortie est 127.

```shell
$ cqt output.txt
zsh: command not found: cqt
$ echo $?
127
```

## `handle` ou `handler` ?

Précision importante avant de commencer. Pour le shell Bash (l'interprète par défaut sur de nombreux systèmes Linux), la fonction à implémenter est `command_not_found_handle`. Pour le shell ZSH, le shell par défaut pour macOS depuis la version Catalina, il faudra implémenter le `command_not_found_handle**r**`. Cependant, `bash` reste toujours disponible sur les MAC modernes.

Si les deux shells partagent beaucoup de similitudes, nous allons nous concentrer sur le shell Bash pour le reste de l'article, qui a l'« avantage » d'être présent sur les systèmes Linux et les macOS récents. 

## Les mains dans le code

Ouvrons le fichier de configuration de shell `~/.bashrc` et ajoutons la fonction `command_not_found_handle`.

```shell
command_not_found_handle() {
    echo "Commande introuvable"
    echo "Veuillez vérifier votre saisie ou utiliser une autre commande."
}
```

Pour prendre en compte les modifications dans la session shell en cours, n'oubliez pas de lancer `source ~/.bashrc`.

```shell
$ vi ~/.bashrc
$ source ~/.bashrc
$ sfeir
Commande introuvable
Veuillez vérifier votre saisie ou utiliser une autre commande.
```

On peut enrichir la fonction en exploitant les arguments à notre disposition.

```shell
command_not_found_handle() {
    local command="$1"
    echo "Oh non ! La commande '$command' est introuvable."
    return 42
}
```

Comme le manuel l'indique, la fonction peut récupérer la commande d'origine. On peut donc l'utiliser comme variable. Ici, on décide de l'afficher. On peut aussi modifier le code de sortie. Dans le cas ci dessous, le code est non nul pour signaler que la commande introuvable est un échec.

```shell
command_not_found_handle() {
    local command="$1"
    echo "Commande introuvable : $command"
    commandes_similaires=$(apropos --long "$command" | awk '{print $1}')
    if [ -n "$commandes_similaires" ]; then
        echo "Vouliez-vous dire l'une de ces commandes similaires ?"
        echo "$commandes_similaires"
    fi
}
```

Dans l'exemple suivant, on va utiliser la variable comme paramètre d'autres fonctions. `apropos` retourne les pages du manuel en lien avec la commande puis `awk` transforme la sortie. Ainsi, quand on va saisir une commande inexistante, une liste d'alternatives sera proposée.

```shell
$ wge
Commande introuvable : wge
Vouliez-vous dire l'une de ces commandes similaires ?
wget
```

## Ne plus réinventer la roue

Nous avons codé pour découvrir et comprendre la fonction `command_not_found_handle` mais il existe des outils qui se basent sur ce qu'on a vu et vont beaucoup plus loin.

[Ubuntu](https://packages.ubuntu.com/search?keywords=command-not-found&searchon=names&exact=1&suite=all§ion=all&ref=sfeir.dev) et [Debian](https://screenshots.debian.net/package/command-not-found?ref=sfeir.dev) possèdent un package `command-not-found` qui peut aller chercher dans les dépôts si on essaie de lancer un programme introuvable sur la machine. Pour les utilisateurs de Homebrew et macOS, le [Homebrew Command Not Found](https://github.com/Homebrew/homebrew-command-not-found?ref=sfeir.dev) permet de reproduire ce comportement. Enfin pour les fans de Oh My Zsh, la fonctionnalité similaire se trouve dans le plugin `[command-not-found](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/command-not-found?ref=sfeir.dev)`.