Quelle est la différence entre “bash script.sh” et “./script.sh”?

43

Si script.sh est juste quelque chose de typique comme

#!/bin/bash
echo "Hello World!"

Existe-t-il un moyen privilégié d’exécuter le script? Je pense que vous devez d’abord le chmod pour qu’il devienne exécutable?

utilisateur72136
la source

Réponses:

57

Pour votre script spécifique, les deux méthodes fonctionneront, sauf que cela ./script.shnécessite une exécution et des bits lisibles, alors que bash script.shne nécessite qu'un bit lisible.


La différence d’exigences en matière d’autorisations tient à la façon dont le programme qui interprète votre script est chargé:

  • ./script.sh fait en sorte que votre shell exécute le fichier comme s’il s’agissait d’un exécutable normal.

Le shell se lance lui-même et utilise un appel système (par exemple execve) pour que le système d'exploitation exécute le fichier dans le processus forké. Le système d'exploitation vérifiera les autorisations du fichier (le bit d'exécution doit donc être défini) et transmettra la demande au chargeur de programmes , qui examinera le fichier et déterminera comment l'exécuter. Sous Linux, les exécutables compilés commencent par un nombre magique ELF , tandis que les scripts commencent par un #!( hashbang ). Un en-tête hashbang signifie que le fichier est un script et doit être interprété par le programme spécifié après le hashbang. Cela permet au script lui-même de dire au système comment interpréter le script.

Avec votre script, le chargeur de programme s’exécutera /bin/bashet passera ./script.sh comme argument de ligne de commande.

  • bash script.shrend votre shell exécuté bashet passé script.shcomme argument de ligne de commande

Donc, le système d'exploitation va se charger bash(même pas regarder script.sh, parce que c'est juste un argument de ligne de commande). Le bashprocessus créé interprétera alors le script.shparce qu'il est passé comme argument de ligne de commande. Parce script.shque n'est lu que par bashun fichier normal, le bit d'exécution n'est pas requis.


Je vous recommande ./script.shcependant d' utiliser , car vous pourriez ne pas savoir quel interprète le script requiert. Laissez donc le programme de chargement le déterminer pour vous.

SkyDan
la source
3
Si le bit exécutable n'est pas défini, vous pouvez également exécuter le script en faisant ". ./Script.sh"
Dog eat cat world
1
@ Dog Tu as raison. Le point est un raccourci pour la commande intégrée 'source', qui exécute le script dans le processus bash en cours. Donc, seul le bit lisible est requis.
SkyDan
5
@Dogeatcatworld Bien que cela soit vrai, exécuter . ./script.shn'est pas la même chose que bash script.sh(ou ./script.sh. Considérons le script #!/usr/bin/python -V<nouvelle ligne> print test.
casey
12
Attention, la recherche d'un script peut entraîner une contamination de la session interactive. Par exemple, si un script modifie la variable d'environnement PATH, cette modification affectera les commandes exécutées après la source. Cette approche devrait en réalité être réservée aux situations dans lesquelles vous dépendez des effets secondaires (scripts de configuration de l’environnement, etc.). Dans les autres cas où vous ne pouvez pas modifier les autorisations, l'exécution de la commande dans la ligne shebang, suivie du nom de script, constitue l'approche la plus sûre.
ctt
6
Notez que si vous sourcez un script dans le répertoire en cours, vous n'avez pas besoin d'utiliser ./ ; dis juste . script.sh. Mais je suis d'accord avec les personnes qui découragent l'utilisation de la .commande sur des scripts qui n'étaient pas censés être invoqués de cette façon. Je suis surpris que personne ne mentionne que, si le script contient des exitcommandes et que vous le sourcez, il pourrait vous déconnecter. Un problème moins grave se poserait si le script effectuait une cd, car cela affecterait également le shell parent (interactif).
Scott
18

bash script.shinvoque le script directement à l'aide du bash.
./script.shutilise le shebang #!/bin/bashpour déterminer comment exécuter.

Si vous voulez vraiment savoir quel binaire est exécuté si vous le faites, bash script.shvous pourriez le savoir which bash.

Donc, dans votre exemple, cela ne fait aucune différence. Oui, vous devezchmod +x script.sh être capable de l'exécuter directement via ./script.sh.

xx4h
la source
2
Eh bien, cela ne fait aucune différence de supposer que /bin/bashc’est le premier bashdans votre cas $PATH.
cjm
Tu as raison. Et le shebang #!/bin/bashne fonctionne que s'il y a un/bin/bash
xx4h
Bash (version 4.2.37) sur mon système exécute les scripts même sans le bit d'exécution défini. Pourquoi dites-vous qu'un bit d'exécution est requis?
SkyDan
Oui, le bit d'exécution n'est nécessaire qu'en appelant via ./script.sh.
xx4h
4

Créez un fichier Delete_Self.sh comme ceci:

 #!/bin/rm

 echo I am still here!

Exécutez ce script comme sh Delete_Self.shvous le verrez "Je suis toujours là!" fait écho en arrière.

Rendez-le exécutable et exécutez-le en tant que ./Delete_Self.sh vous verrez que rien ne sera renvoyé, alors que le fichier Delete_Self.shlui-même est parti.

Donc la différence est que:

  • bash script.shva ignorer le #! line, parce que bash est spécifié comme programme d’exécution de script.sh.
  • ./script.shva lire le #! ligne pour déterminer le programme à exécuter script.sh.
David
la source
+1 pour le bel exemple
ThisaruG
1

Outre les autres réponses, connaître la différence entre l'exécution d'un script via ./script.sh(i) et source ./script.sh(ii) est utile - La version (i) crée un nouveau shell dans lequel exécuter la commande, alors que (ii) l'exécute dans le dossier shell actuel - qui peut être obligatoire si l'exécutable modifie les variables d'environnement qui doivent être préservées après la fermeture de l'exécutable. Par exemple, pour activer un environnement Python Conda, vous devez utiliser les éléments suivants:

source activate my_env

NB Une autre alternative à sourcecelle que vous pouvez rencontrer est la fonction .intégrée, à savoir

. activate my_env
einonm
la source