URL: https://linuxfr.org/users/raphj/journaux/shebang-usr-bin-env-sh-teste-et-approuve Title: Shebang #!/usr/bin/env sh : testé et approuvé Authors: raphj Date: 2019年05月02日T13:55:45+02:00 License: CC By-SA Tags: bash, shell, posix, standard et shebang Score: 26 Je prends grand soin à éviter les bashismes pour que mes scripts puissent tourner sur n’importe quel système, quelque soit le shell présent, pourvu qu’il soit compatible POSIX. Mes scripts shell son préfixés avec le shebang `#!/usr/bin/env sh` et jusqu’à maintenant, je le faisais purement pour la bonne pratique, en me disant que je pourrais très bien utiliser `#!/bin/sh`, et mon environnement d’exécution se débrouillera toujours pour trouver un shell compatible POSIX pour exécuter mon script. Et si le système ne respecte pas la [hiérarchie standard](https://fr.wikipedia.org/wiki/Filesystem_Hierarchy_Standard), j’aurai un problème dans tous les cas puisqu’on spécifie de toute façon `/usr/bin/env` dans l’autre shebang. Or, quel système, en pratique, fournirait `/usr/bin/env` et pas `/bin/sh` ? D’ailleurs, il me semblait plus probable de tomber sur un système qui a un `/bin/sh` et pas un `/usr/bin/env`, la description de `/usr/bin` étant « Binaires exécutables qui ne sont pas déjà présents dans /bin et donc *pas indispensables à un système minimaliste* » (d’ailleurs, pourquoi `env` est dans `/usr/bin` et pas dans `/bin` ?). Ce qui ressemble effectivement à un point négatif à l'utilisation de `#!/usr/bin/env sh`. Les systèmes que j’ai l’habitude d’utiliser utilisent `dash` comme shell par défaut. Tout va bien dans le meilleur des mondes, c’est un shell minimaliste qui à priori ne propose que très peu d’ajouts par rapport à la norme POSIX. Ce qui veut dire que si un script tourne chez moi, il devrait tourner partout pourvu que ses dépendances soient installées. Et là, j’utilise un système qui utilise `bash` pour `/bin/sh`. Je m’en rends vite compte, parce que pour vérifier qu’une construction n’est pas un bashisme, je lance `sh` et je la colle dedans. Sauf que là, les bashismes passaient (aka [Comment ça, $EPOCHREALTIME fonctionne dans `sh` alors que c’est une fonctionnalité du tout nouveau Bash 5 ?](https://linuxfr.org/news/fedora-30)). Ce qui veut aussi dire que mes scripts avec le shebang `#!/usr/bin/env sh` se mettent à fonctionner même s’ils contiennent des bashismes (et bon, si je me mets à avoir besoin des bashismes, peut-être qu’il est temps d’utiliser un autre langage de script installé par défaut sur la plupart des systèmes). Que faire ? Je ne vais pas changer le shell par défaut du système, parce que c’est certainement un bon moyen de chercher les ennuis voire casser le démarrage (il doit y avoir des scripts plein partout se déclarant avec `/bin/sh` ou `/usr/bin/env sh` et qui contiennent en fait des bashismes). Grâce à l’utilisation de `#!/usr/bin/env sh`, la solution est simple : installer `dash` ou n’importe quel autre shell limité à la norme POSIX, créer un lien `$HOME/bin/sh` pointant vers ce shell et avoir `$HOME/bin` dans mon `$PATH`, et paf ça fonctionne (initialement, l’idée de faire ce lien dans `/usr/local/bin` m’a chatouillé l’esprit deux secondes, mais à la troisième seconde je me suis dit que ça avait un bon potentiel pour semer le même chaos que celui qui est décrit dans le paragraphe précédent). Ouf, ma vie n’a pas changé, je vais pouvoir continuer à écrire mes scripts en toute tranquillité indépendamment du shell par défaut du système que j’utilise. N’avais-je pas utilisé `#!/usr/bin/env sh`, j’étais bon pour changer tous mes shebangs. Un bon gros `sed` sur tout mon `$HOME`. `#!/usr/bin/env sh`, c’est bon, mangez-en.