11/09/2024

Commandes et SystèmeLinux

Linux : comment vérifier la compatibilité POSIX d’un script avec shellsheck ?

I. Présentation

Dans ce tutoriel, nous allons voir ce qu'est la norme POSIX et comment vérifier si un script Bash est compatible avec cette norme à l'aide de l'outil "shellcheck". Cela vous permettra d'être sûr qu'un script peut être exécuté sur tous les systèmes d'exploitation UNIX et shells compatibles POSIX.

Les systèmes d'information actuels étant souvent composés de nombreux systèmes d'exploitation Unix différents, il est important de pouvoir s'assurer de la bonne exécution d'un ensemble de commandes sans avoir à les tester manuellement sur plusieurs systèmes, shells, versions, etc.

Sous Linux, un shell (ou terminal) est un logiciel qui fait la liaison entre l’utilisateur et le système d’exploitation. Selon le shell utilisé, différentes options, commandes, syntaxes ou variables peuvent être présentes et prises en compte ou non.

Vérifier la compatibilité POSIX d'un script peut être nécessaire dans de nombreux contextes, notamment quand on met à disposition des outils pouvant être exécutés sur des systèmes dont on ne connaît pas par avance la composition, par exemple, lors de leur mise à disposition publique.

II. La norme POSIX, qu'est-ce que c'est ?

POSIX (Portable Operating System Interface) est un standard créé en 1988 par l’IEEE Computer Society qui spécifie les bases de tout système UNIX, dont l’interface de scripting (Bourne Shell : sh), les commandes basiques, etc. Il a été initialement conçu pour assurer une compatibilité minimale entre les systèmes d’exploitation UNIX.

Il existe plusieurs versions de POSIX, nommées “POSIX:année” et la dernière en date est la “POSIX.1-2024”.

Le fait de respecter cette norme permet donc une interopérabilité des scripts et programmes, qui pourront être utilisés sur différents systèmes d’exploitation, mais aussi une fiabilité qui rendra les scripts moins susceptibles aux problèmes dus aux variations (parfois très subtiles) entre les implémentations des shells et systèmes d’exploitation. Enfin, cela facilite également la maintenance, les scripts conformes suivant une syntaxe commune et bien définie.

Plus concrètement, lorsque l’on dit qu’un script est “compatible POSIX”, cela signifie plusieurs choses :

  • Portabilité

Un script qui est dit “compatible POSIX” peut être exécuté sur tout système conforme à POSIX sans nécessiter de modifications. Cela inclut des commandes, des syntaxes et des comportements de script uniformes.

  • Utilisation de syntaxe standard

Ce script utilise des commandes et des options standardisées par POSIX. Cela peut être des détails de syntaxe qui semblent accessoires, mais qui sont en réalité importants. Par exemple, l'utilisation de “#!/bin/sh” au lieu de “#!/bin/bash pour la ligne de shebang, car "sh" est une interface shell conforme POSIX tandis que "bash" peut avoir des extensions non conformes.

  • Absence de fonctions spécifiques au shell

Ce script évite d'utiliser des fonctionnalités spécifiques à un shell particulier (comme certaines extensions de "bash"). Il se limite aux fonctionnalités définies par le standard POSIX, telles que les boucles “for, les tests de fichiers “test, et les commandes de base comme “echo, “cp”, “mv”, etc..

  • Conformité aux normes POSIX pour les outils

Les outils et commandes utilisés dans le script, tels que “awk, “sed”, “grep”, sont appelés avec des options et des arguments qui sont conformes aux spécifications POSIX. Car la norme POSIX porte également sur les options des commandes et la manière des les utiliser et les appeller.

Mon shell actuel est-il compatible POSIX ?

Vous pouvez rapidement voir si votre shell actuel est compatible POSIX, c’est-à-dire s’il n’exécutera des commandes et scripts que s’il sont compatibles POSIX et refusera d’utiliser ses propres fonctions non compatibles POSIX. Il faut pour cela utiliser la variable d’environnement “$SHELOPTS” et vérifier qu’elle contient la mention “posix” quelque part :

 Vérification de la compatibilité et démarrage d’un bash POSIX.
Vérification de la compatibilité et démarrage d’un bash POSIX.

Ici, mon shell initial n’était pas chargé en mode “POSIX-compliant”, ce que j’ai fait ensuite avec l’option “-posix”. Ma seconde vérification fait bien apparaître la mention “posix”. Certaines commandes intégrées pourront avoir une différence de comportement due à l’utilisation d’une implémentation POSIX.

En revanche, certaines fonctionnalités intéressantes des shells que vous utiliserez ne seront peux être pas présentes et utilisables dans un contexte POSIX. Aussi, il faudra parfois revoir certaines parties de vos scripts. Pour vous donner un exemple, bash permet de définir des fonctions comme suivant :

function nom_fonction() {
# code
}

Cette écriture n’est pas compatible POSIX, alors que la suivante oui :

nom_fonction() {
	# code
}

Le fonctionnement sera le même, mais cette différence subtile suffira à déclarer votre script comme non compatible POSIX. Voici par exemple la différence d’exécution d’un script simple via le shell “bash”, à gauche, et via le shell “sh” (POSIX), droite :

Différence d’exécution du même script dans un shell POSIX et un shell non POSIX.
Différence d’exécution du même script dans un shell POSIX et un shell non POSIX.

L’exécution via le shell “sh” (POSIX) s’est soldée par une erreur, car la déclaration de la fonction en ligne 8 (la fonction “f2”) ne respecte pas la syntaxe POSIX. Dans le cas d’un script qui serait déployé et exécuté de façon automatisée sur un ensemble de serveurs, dont certains avec un shell par défaut en “sh”, le script ne s’exécuterait pas correctement dans le cas d’une fonction telle que la fonction “f2” de mon script.

Vous voyez donc que cette norme est exigeante, mais la respecter comporte plusieurs intérêts qui peuvent être importants en fonction des contextes d’utilisation de vos scripts et programmes.

III. Mon script est-il compatible POSIX ?

Nous allons à présent apprendre à vérifier si un script est compatible avec la norme POSIX et, si ce n’est pas le cas, identifier les directives, options, commandes ou syntaxes qui posent un problème.

Commençons par installer l’outil nécessaire à cette tâche sur notre système : shellsheck

# Pour les systèmes basés sur Debian
sudo apt install shellcheck -y

# Pour les systèmes basés sur Red Hat

sudo yum install shellcheck -y

Maintenant que “shellsheck” est installé, nous pouvons vérifier sa version :

# Identification de la version de shellcheck
$ shellcheck --version

ShellCheck - shell script analysis tool
version: 0.10.0
license: GNU General Public License, version 3
website: https://www.shellcheck.net

Si vous avez en retour de cette commande une version affichée, c’est que vous êtes prêt à l’utiliser. Dans un deuxième temps, il nous faut bien sûr un script à analyser et l’indiquer à “shellcheck” :

# Vérifier qu'un script est POSIX compatible
shellcheck <mon_script.sh>

# Exemple

shellcheck script.sh

Voici un exemple de retour possible de “shellcheck”. Comme vous pouvez le voir, plusieurs non-conformités sont relevées :

 Exemple de note “info” remontée par “shellcheck”.
Exemple de note “info” remontée par “shellcheck”.

Ici, “shellcheck” m’indique que les variables doivent être mises entre double quote. Ou encore :

 Exemple d’erreur remontée par “shellcheck”.
Exemple d’erreur remontée par “shellcheck”.

Ici, “shellcheck” m’indique que le contrôle de l’existence d’un fichier avec l’option “-f” n’est pas compatible POSIX lorsque le nom du fichier vérifié possède un wildcard (“*”).

Si “shellcheck” ne vous retourne strictement rien, c’est que votre script est 100% compatible POSIX et qu’il n’a donc rien trouvé à y redire.

Sans surprise, si j’analyse mon petit script d’exemple du chapitre précédent, l’analyse via la commande “shellcheck” m’indique que la déclaration de la fonction “f2” n’est pas conforme. Le mot-clé “function” n’étant pas reconnu dans le standard POSIX :

 Exemple d’avertissement remonté par “shellcheck”.
Exemple d’avertissement remonté par “shellcheck”.

Les non-conformités relevées peuvent être de différents niveaux, en fonction du type et de la gravité de l’élément identifié : warning, error, info, style. Pour l’instant, et c’est bien dommage, nous n’avons pas les détails de l’importance et de la raison de ces différents niveaux (source : Github – koalaman/shellcheck - Wiki). Dans le doute et surtout si votre script a un besoin élevé de compatibilité, il vaut mieux tout corriger.

Vous pouvez notamment ajouter l’option “-S <niveau>” pour n’avoir en retour que les non-conformités du niveau choisi :

# Analyse shellcheck avec uniquement les erreurs
shellcheck -S error Downloads/Extract-Cat-Scale.sh

Enfin et surtout, vous trouverez en fin d’analyse l’ensemble des types d’erreurs ou non-conformité relevées ainsi que des liens vers le détail en ligne de celles-ci :

For more information:
https://www.shellcheck.net/wiki/SC2144 -- -f doesn't work with globs. Use a...
https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ..

C’est le plus important pour bien comprendre les erreurs remontées. Le contenu accessible sur ces liens explique très bien la raison de l’erreur et propose notamment des exemples de codes corrigés.

IV. Version en ligne

L’outil “shellcheck” dispose également d’une version en ligne, dans laquelle vous pourrez charger vos scripts pour effectuer une analyse de leur compatibilité POSIX et obtenir les non-conformités identifiées :

 Utilisation de la version en ligne de “shellcheck”.
Utilisation de la version en ligne de “shellcheck”.

Attention cependant, cette utilisable en ligne peut ne pas convenir à tous les contextes, particulièrement si votre script contient des informations sensibles (données métiers, noms, mots de passe), des fonctions relatives à des opérations de sécurité (chiffrement), etc. Soyez donc vigilant sur ce que vous y déposez et en cas de doute, préférez la version locale.

IV. Conclusion

Nous avons dans cet article fait un bref rappel de ce qu’est la norme POSIX et de son intérêt dans le cadre de la rédaction de script Bash. Nous avons également vu comment facilement et rapidement voir si un script est compatible avec la norme POSIX grâce à l’outil “shellcheck” et si ce n’est pas le cas, pour quelle raison.

L’intérêt de “shellcheck” est qu’il fournit des détails et des recommandations sur les non-conformités identifiées, ce qui permet d’en apprendre beaucoup sur les bonnes pratiques de rédaction d’un script Bash.

author avatar
Mickael Dorigny Co-founder
Co-fondateur d'IT-Connect.fr. Auditeur/Pentester chez Orange Cyberdéfense.
Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Envoyer par mail

2 commentaires sur “Linux : comment vérifier la compatibilité POSIX d’un script avec shellsheck ?

  • L’outil vérifie la syntaxe du script. Il ne vérifie pas si le script produira le résultat attendu sous la norme Posix. Les programmes appelés doivent aussi produire un résultat conforme à Posix. Voir la variable d’environnement POSIXLY_CORRECT (sous GNU). Faire tous les tests unitaires avec cette variable positionnée.

    Il y aura encore des subtilités qui peuvent péter à la figure (taille des buffers pour les pipes par exemple, si un programme appelé a été mal écrit).

    Répondre
  • Bonjour,

    dans le 1er paragraphe de « Mon shell actuel est-il compatible POSIX ? »
    il manque un « L » dans “$SHELOPTS”

    Répondre

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.