Florent Jardin   Conférences  Archives  À propos

Poissons et coquillages

En tant que pur produit académique des années 2010, mon langage de script de prédilection a toujours été le Bash (Bourne Again Shell). Non sans ignorer qu’il ait pu en exister d’autres, je ne me suis jamais vraiment tourné vers d’autres shells pour automatiser les tâches du quotidien dans mon métier de DBA.

Et pour cause, j’ai administré des centaines de serveurs de distributions très variées et il n’était pas bien vu d’installer des dépendances systèmes lourdes pour enrichir des scripts Python ou Perl. Nous apprenions donc à écrire des scripts portables et universels, compatibles partout où nous déposions nos valises.

Me suis-je enfermé dans un dogme conservateur, en m’interdisant de facto à me tourner vers des shells modernes et bien plus aisés à appréhender ?


Beurk, le Bash

Ne faisons pas de détour, le Bash c’est moche. Puissant, pratique, universel, mais moche.

Vous pourriez penser que c’est un avis parfaitement subjectif, et qu’il ne faut pas juger un livre à sa couverture… mais avouez-le, une partie de vous pense sensiblement la même chose que moi. Combien d’heures ai-je pu perdre durant ma courbe d’apprentissage du langage, à cause d’un grand nombre de subtilités et de pièges de syntaxes ?

Entre les assignations sans espace autour du signe =, les accolades {} pour les variables contenant un signe _, les backticks ` ` pour les commandes subshells, ou encore les doubles crochets [[ ... ]] pour les comparaisons non-POSIX, il y a de quoi s’arracher les cheveux.

Certain·e·s y verront une forme d’esthétisme ou de tradition d’une culture informatique, mais personnellement je trouve que c’est un langage qui vieillit mal, très mal. Vous ne vous offusqueriez pas non plus si je devais vous témoigner mon désamour le Perl, n’est-ce pas ?

# une comparaison de deux variables
[[ "$a" == "$b" ]]

# une addition et une affectation
z=$(( $x + $y ))

# une boucle for
for i in $(seq 1 10); do
    echo $i
done

# un switch case
case $1 in
    1) echo "un";;
    2) echo "deux";;
    *) echo "autre";;
esac

# une chaîne en minuscule
a=${a,,}

# une gestion des erreurs de commandes chaînées
some_command | another_command
if [[ ${PIPESTATUS[0]} -ne 0 || ${PIPESTATUS[1]} -ne 0 ]]; then
    echo "Une des commandes a échoué"
fi

Le Bash est apparu l’année de ma naissance, en 1989. Il a été conçu en opposition au Bourne Shell (sh) pour apporter des fonctionnalités de programmation plus avancées. Il est devenu le shell par défaut de la plupart des distributions Linux, et est devenu un standard pour tous les scripts à travers le monde entier.

Fort de ses années de succès, et de son emprise sur le monde Unix, le Bash s’impose parfois comme la première porte vers la programmation pour des administrateurices système ou les étudiant·e·s en informatique. Et il faut accepter que la qualité de ses premiers scripts n’est pas toujours au rendez-vous. Souvenez-vous des longues heures passées sur StackOverflow à trouver la syntaxe la plus lisible ou la plus efficace, car les réponses se révélaient aussi variées que touffues !

Et c’est l’un des plus gros problèmes que je trouve au Bash : ce langage de programmation est exigeant, excentrique, voire idiosyncratique, et qui ne pardonne pas les erreurs. Un des paradoxes que j’associe au Bash est qu’il peut ne pas être considéré comme un véritable langage de programmation, réduisant ainsi la volonté et l’effort de l’apprendre en profondeur par une large communauté de professionnel·le·s.

Et si vos scripts Bash sont nuls, utilisez un autre langage.


L’ami Fish, Friendly Interactive Shell

Je suis tombé sur Fish par hasard, alors que je questionnais mon usage quotidien sur ZSH. Sur mon poste personnel, j’ai étendu mon expérience passée sur le Bash avec une configuration ZSH enrichie de Oh My Zsh. C’était un peu le jour et la nuit dans l’interaction avec mes terminaux : la navigation, les suggestions, les thèmes, les plugins, tout est plus fluide et plus agréable. Sa compatibilité avec Bash m’avait alors évité de tout réapprendre.

Fish répond au besoin de modernité et de simplicité que je cherche sans vraiment le savoir. Contrairement à ZSH, un grand nombre de fonctionnalités sont disponibles sans aucune configuration préalable ou plugin à activer.

Assistance à la commande

  • Recopie la commande incomplète et en erreur sans besoin de naviguer dans l’historique
  • Accès à l’historique partiel avec les touches directionnelles dès la première frappe au clavier
  • Proposition de chemins avec la complétion de la touche Tab, suivie des touches directionnelles

Auto-suggestions des chemins et des options d’une grande majorité des outils

  • Mémoire des précédents répertoires parcourus
  • Support très complet des commandes Git, notamment le git rebase -i ❤️

Coloration plus poussée des commandes

  • une couleur différente par mot selon la syntaxe employée (variables, chemin, options)
  • un rouge prononcé pour les commandes inconnues

Un langage qui vous veut du bien

Pour revenir au sujet principal de cet article, Fish révolutionne notre rapport avec la rédaction de scripts. Fini les pièges et la syntaxe qui nous ont tenu en otage durant des années. Les choses deviennent bien plus simples et lisibles.

# une comparaison de deux variables
test "$a" = "$b"

# une addition et une affectation
set z (math $x + $y)

# une boucle for
for i in (seq 1 10)
    echo $i
end

# un switch case
case $argv[1]
    1; echo "un"
    2; echo "deux"
    *; echo "autre"
end

# une chaîne en minuscule
set a (string lower $a)

# une gestion des erreurs de commandes chaînées
some_command | another_command
if contains 1 $pipestatus
    echo "Une des commandes a échoué"
end

L’investissement initial pour perdre ses habitudes acquises avec Bash est modéré, notamment le remplacement de export ou de l’assignation = par la méthode set -x ou set -u respectivement. Mais l’enrichissement du langage par quelques nouveaux mots-clés permet d’alléger le script avec des syntaxes claires et lisibles (contains, math ou string présents dans l’exemple ci-dessus).

L’ajout de plugins communautaire n’est pas en reste, si comme moi, vous en consommiez avec Oh-My-ZSH. L’outil Fisher s’installe dans votre ~/.config/fish et donne accès à un gestionnaire complet et sobre. Pour ma part, j’ai pu rapidement combler mon besoin de charger les variables d’environnement fournies par l’agent SSH (ssh-agent) lors du démarrage de ma session.

$ fisher install danhper/fish-ssh-agent
fisher install version 4.4.5
Fetching https://api.github.com/repos/danhper/fish-ssh-agent/tarball/HEAD
Installing danhper/fish-ssh-agent
           /home/florent/.config/fish/functions/__ssh_agent_is_started.fish
           /home/florent/.config/fish/functions/__ssh_agent_start.fish
           /home/florent/.config/fish/conf.d/fish-ssh-agent.fish
Updated 1 plugin/s

Pas de mystère, ni d’arcanes magiques, votre environnement est enrichi de nouvelles fonctions et de scripts de démarrage, développés en Fish.


Osons la modernité

La documentation du projet est très bien fournie. En plus de la page Tutorial, vous trouverez une page dédiée aux utilisateurs de Bash pour vous aider à réussir votre transition. Pour ma part, j’y retrouve des syntaxes bien plus proches du Python, et c’est un vrai plaisir.

Le projet est vivant, avec un rythme de versions régulier. Je me suis surpris moi-même à ne pas en avoir entendu parler par d’autres collègues ou auprès des auteurices de blogs que je suis. Au cours des dernières années, la communauté francophone a essaimé quelques bons articles qui complètent le mien.

Ces temps-ci, je fais évoluer mon expérience d’utilisateur de Linux avec une transition vers Wayland et SwayWM (j’y reviendrais dans un autre article). Je ne le cache pas, la tentation de remplacer mes scripts Bash qui gèrent mes thèmes ou les composants swaybar, est forte, très forte.

De quoi occuper mes prochaines longues soirées d’hiver.