GNU/Linux >> Tutoriels Linux >  >> Linux

Quand dois-je utiliser #!/bin/bash et quand #!/bin/sh ?

En bref :

  • Il existe plusieurs shells qui implémentent un sur-ensemble de la spécification POSIX sh. Sur différents systèmes, /bin/sh peut être un lien vers ash, bash, dash, ksh, zsh, etc. (Cependant, il sera toujours compatible sh - jamais csh ou fish.)

  • Tant que vous vous en tenez à sh fonctionnalités uniquement, vous pouvez (et probablement même devriez) utiliser #!/bin/sh et le script devrait fonctionner correctement, quel que soit le shell.

  • Si vous commencez à utiliser des fonctionnalités spécifiques à bash (par exemple, des tableaux), vous devez spécifiquement demander bash - car, même si /bin/sh invoque déjà bash sur votre système, il se peut qu'il ne soit pas sur tous les autres système, et votre script ne s'y exécutera pas. (La même chose s'applique bien sûr à zsh et ksh.) Vous pouvez utiliser shellcheck pour identifier les bashismes.

  • Même si le script est destiné à un usage personnel uniquement, vous remarquerez peut-être que certains systèmes d'exploitation changent /bin/sh pendant les mises à niveau – par ex. sur Debian, c'était bash, mais plus tard, il a été remplacé par un tiret très minimal. Scripts qui utilisaient des bashismes mais avaient #!/bin/sh cassé soudainement.

Cependant :

  • Même #!/bin/bash n'est pas très correct. Sur différents systèmes, bash peut vivre dans /usr/bin ou /usr/pkg/bin ou /usr/local/bin .

  • Une option plus fiable est #!/usr/bin/env bash , qui utilise $PATH. (Bien que le env l'outil lui-même n'est pas non plus strictement garanti, /usr/bin/env fonctionne toujours sur plus de systèmes que /bin/bash fait.)


Utilisez le shebang correspondant au shell que vous avez réellement utilisé pour développer et déboguer votre script. C'est à dire. si votre shell de connexion est bash , et que vous exécutez votre script en tant qu'exécutable dans votre terminal, utilisez #!/bin/bash . Ne supposez pas simplement que puisque vous n'avez pas utilisé de tableaux (ou quoi que ce soit bash fonction que vous connaissez), vous êtes sûr de choisir la coque que vous aimez. Il existe de nombreuses différences subtiles entre les coques (echo , fonctions, boucles, nommez-les) qui ne peuvent être découvertes sans des tests appropriés.

Considérez ceci :si vous laissez #!/bin/bash et vos utilisateurs ne l'ont pas, ils verront un message d'erreur clair, quelque chose comme

Error: /bin/bash not found

La plupart des utilisateurs peuvent résoudre ce problème en moins d'une minute en installant le package approprié. Par contre, si vous remplacez le shebang par #!/bin/sh et testez-le sur un système où /bin/sh est un lien symbolique vers /bin/bash , vos utilisateurs qui n'ont pas bash sera en difficulté. Ils verront très probablement un message d'erreur énigmatique comme :

Error in script.sh line 123: error parsing token xyz

Cela peut prendre des heures à réparer, et il n'y aura aucune idée du shell qu'ils auraient dû utiliser.

Il n'y a pas beaucoup de raisons pour lesquelles vous voudriez utiliser un shell différent dans le shebang. L'une des raisons est que le shell que vous avez utilisé n'est pas très répandu. Une autre est de gagner en performance avec sh ce qui est beaucoup plus rapide sur certains systèmes, ET votre script sera un goulot d'étranglement pour les performances. Dans ce cas, testez soigneusement votre script avec le shell cible, puis modifiez le shebang.


Vous ne devriez jamais utiliser #! /bin/sh .

Vous ne devriez jamais utiliser les extensions bash (ou zsh, ou fish, ou ...) dans un script shell.

Vous ne devriez écrire que des scripts shell qui fonctionnent avec any implémentation du langage shell (y compris tous les programmes "utilitaires" qui accompagnent le shell lui-même). De nos jours, vous pouvez probablement prendre POSIX.1-2001 (pas -2008) comme faisant autorité pour ce que le shell et les utilitaires sont capables de faire, mais sachez que vous pourriez un jour être appelé à porter votre script sur un système hérité (par exemple Solaris ou AIX) dont le shell et les utilitaires ont été gelés vers 1992.

Quoi, sérieusement ? !

Oui, sérieusement.

Voici le truc :Shell est un terrible langage de programmation. La seule chose qu'il a à faire est que /bin/sh est le seul et unique interpréteur de scripts que tous L'installation d'Unix est garantie d'avoir.

Voici l'autre chose :une itération de l'interpréteur principal de Perl 5 (/usr/bin/perl ) est plus susceptibles d'être disponibles sur une installation Unix sélectionnée au hasard que (/(usr|opt)(/(local|sfw|pkg)?)?/bin/bash est. D'autres bons langages de script (Python, Ruby, node.js, etc. - j'inclurai même PHP et Tcl dans cette catégorie lors de la comparaison avec le shell) sont également à peu près aussi disponibles que bash et d'autres shells étendus.

Par conséquent, si vous avez la possibilité d'écrire un script bash, vous avez la possibilité d'utiliser un langage de programmation qui n'est pas terrible à la place.

Maintenant, simple scripts shell, le genre qui exécute juste quelques programmes dans une séquence à partir d'un travail cron ou quelque chose, il n'y a rien de mal à les laisser comme scripts shell. Mais les scripts shell simples n'ont pas besoin de tableaux ou de fonctions ou de [[ même. Et vous ne devriez écrire que compliqué scripts shell lorsque vous n'avez pas d'autre choix. Les scripts Autoconf, par exemple, sont toujours des scripts shell. Mais ces scripts doivent s'exécuter sur chaque incarnation de /bin/sh qui est pertinent pour le programme en cours de configuration. et cela signifie qu'ils ne peuvent utiliser aucune extension. Vous n'avez probablement pas à vous soucier des anciens Unix propriétaires de nos jours, mais vous devriez probablement devrait se soucier des BSD open-source actuels, dont certains n'installent pas bash par défaut, et des environnements intégrés qui ne vous donnent qu'un shell minimal et busybox .

En conclusion, au moment où vous vous trouvez voulant une fonctionnalité qui n'est pas disponible dans le langage shell portable, c'est un signe que le script est devenu trop compliqué pour rester un script shell. Réécrivez-le plutôt dans un meilleur langage.


Linux
  1. Comment Linux gère-t-il plusieurs séparateurs de chemins consécutifs (/home////nom d'utilisateur///fichier) ?

  2. L'espace est-il autorisé entre # ! Et /bin/bash à Shebang ?

  3. Pourquoi /bin/sh pointe-t-il vers /bin/dash et non /bin/bash ? ?

  4. Quelle est la différence entre /bin/false et /sbin/nologin en tant que shell de l'utilisateur nologin

  5. Installer les binaires dans /bin, /sbin, /usr/bin et /usr/sbin, interactions avec --prefix et DESTDIR

Aucune raison d'avoir un Shebang pointant vers /bin/sh plutôt que /bin/bash ?

Linux – Fusionner /usr/bin et /usr/sbin dans /bin (gnu/linux) ?

Quelle est la différence entre #!/usr/bin/env bash et #!/usr/bin/bash ?

cmake --version pointe vers /usr/bin/cmake tandis que cmake pointe vers /usr/local/bin

Quand dois-je utiliser /dev/shm/ et quand dois-je utiliser /tmp/?

Différence entre /bin et /usr/bin