Calculer « 1/(40rods/hogshead) → L/100km » depuis l’invite Zsh
Vincent Bernat
J’ai souvent besoin d’un calcul rapide ou de convertir une unité en une autre.
Plutôt que de recourir à un outil séparé, quelques lignes de configuration Zsh
transforment = en calculatrice. En tapant = 660km / (2/3)c * 2 -> ms,
j’obtiens 6.60457 ms1 sans quitter mon terminal, grâce à l’éditeur
de ligne de Zsh.
L’alias =#
L’idée de base est simple : définir = comme alias vers une calculatrice en
ligne de commande. Je préfère Numbat, une calculatrice scientifique gérant
les conversions d’unités. Qalculate est une autre option2. Si aucun
des deux n’est disponible, nous nous rabattons sur le module zcalc intégré à
Zsh.
Comme la commande alias utilise = comme séparateur entre nom et valeur, nous
modifions directement le tableau associatif aliases :
if (( $+commands[numbat] )); then aliases[=]='numbat -e' elif (( $+commands[qalc] )); then aliases[=]='qalc' else autoload -Uz zcalc aliases[=]='zcalc -f -e' fi
Ainsi, = 847/11 devient numbat -e 847/11.
Le problème des caractères spéciaux#
Le premier problème apparaît vite. Taper = 5 * 3 échoue : Zsh interprète *
comme un motif pour fichiers avant de le transmettre à la calculatrice. Le même
souci se pose avec d’autres caractères spéciaux pour Zsh, comme > ou |. Il
faut protéger l’expression :
$ = '5 * 3' 15
Nous corrigeons cela en nous appuyant sur l’éditeur de ligne de Zsh pour placer l’expression entre guillemets avant son exécution.
Protéger l’expression automatiquement avec ZLE#
Zsh appelle accept-line quand on valide une commande. Remplaçons-le par une
fonction qui détecte le préfixe = et protège l’expression :
_vbe_calc_accept() { case $BUFFER in "="*) typeset -g _vbe_calc_expr=$BUFFER # not used yet BUFFER="= ${(q-)${${BUFFER#=}# }}" ;; esac zle .accept-line } zle -N accept-line _vbe_calc_accept
Quand on tape = 5 * 3 puis ↲, _vbe_calc_accept protège
l’expression avec le drapeau (q-) et réécrit la
ligne en = '5 * 3' avant de la valider avec .accept-line. En bonus, vous
pouvez économiser quelques caractères avec =5*3 ! 🚀
Nous pouvons désormais effectuer des calculs et des conversions d’unités directement depuis le shell. Zsh protège automatiquement les expressions :
$ = '1 + 2' 3 $ = 'pi/3 + pi |> cos' -0.5 $ = '17 USD -> EUR' 14.7122 € $ = '180*500mg -> g' 90 g $ = '5 gigabytes / (2 minutes + 17 seconds) -> megabits/s' 291.971 Mbit/s $ = 'now() -> tz("Asia/Tokyo")' 2026-03-22 22:00:03 JST (UTC +09), Asia/Tokyo $ = '1 / (40 rods / hogshead) -> L / 100km' 118548 × 0.01 l/km

Conserver l’expression originale dans l’historique#
En l’état, Zsh enregistre l’expression protégée dans l’historique. Il faut la déprotéger avant de la soumettre à nouveau, sinon ZLE la protège une seconde fois. Bart Schaefer m’a fourni une solution pour stocker la version originale :
_vbe_calc_history() { return ${+_vbe_calc_expr} } add-zsh-hook zshaddhistory _vbe_calc_history _vbe_calc_preexec() { (( ${+_vbe_calc_expr} )) && print -s $_vbe_calc_expr unset _vbe_calc_expr return 0 } add-zsh-hook preexec _vbe_calc_preexec
Le hook zshaddhistory renvoie 1 quand une expression est en cours
d’évaluation, indiquant à Zsh de ne pas enregistrer la commande. Le hook
preexec ajoute ensuite la commande originale, non protégée, avec print -s.
Le code complet est disponible dans mon zshrc. Une alternative courante est
le modificateur noglob. En utilisant to au lieu de -> pour les
conversions d’unités, il couvre 90 % des cas. Pour une astuce similaire avec
l’éditeur de ligne de Zsh, voyez comment j’utilise les expansions automatiques
des alias pour corriger les fautes de frappe courantes.
-
C’est le temps le plus court pour qu’un paquet fasse l’aller-retour entre Paris et Marseille par fibre optique. ↩︎
-
Qalculate est plus strict avec les unités. Par exemple, il interprète « Mbps » comme mégabarn par picoseconde : ☢️
↩︎$ numbat -e '5 MB/s -> Mbps' 40 Mbps $ qalc 5 MB/s to Mbps 5 megabytes/second = 0.000005 B/ps