Quelle est la différence entre l'exécution d'un script Bash et son sourcing?

284

Quelle est la différence entre l’exécution d’un script Bash tel que A et la création d’un script Bash tel que B?

A
> ./myscript

B
> source myscript
Scottie T
la source
Vous pouvez lire ceci: bash.cyberciti.biz/guide/Source_command
ERU

Réponses:

346

Réponse courte

Sourcing un script exécuter les commandes dans le courant processus shell.

L'exécution d' un script exécutera les commandes dans un nouveau processus shell.

Utilisez source si vous souhaitez que le script modifie l'environnement dans votre shell en cours d'exécution. utiliser exécuter autrement.

Si vous êtes toujours confus, lisez la suite.

Terminologie

Pour clarifier une certaine confusion concernant la syntaxe à exécuter et la syntaxe à utiliser comme source:

./myscript

Cela s'exécutera à myscript condition que le fichier soit exécutable et situé dans le répertoire en cours. Le point et la barre oblique ( ./) indiquent le répertoire en cours. Cela est nécessaire car le répertoire en cours ne figure généralement pas (et ne devrait normalement pas l'être) dans $PATH.

myscript

Ceci s’exécutera myscript si le fichier est exécutable et situé dans un répertoire de $PATH.

source myscript

Ce sera la source myscript . Le fichier ne doit pas nécessairement être exécutable, mais il doit s'agir d'un script shell valide. Le fichier peut être dans le répertoire en cours ou dans un répertoire dans $PATH.

. myscript

Ce sera également source myscript . Cette "orthographe" est officielle telle que définie par POSIX . Bash défini sourcecomme un alias au point.

Manifestation

Considérez myscript.shavec le contenu suivant:

#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD

Avant d'exécuter le script, nous vérifions l'environnement actuel:

$ env | grep FOO
$ echo $PWD
/home/lesmana

La variable FOOn'est pas définie et nous sommes dans le répertoire de base.

Maintenant, nous exécutons le fichier:

$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Vérifiez à nouveau l'environnement:

$ env | grep FOO
$ echo $PWD
/home/lesmana

La variable FOOn'est pas définie et le répertoire de travail n'a pas changé.

La sortie du script indique clairement que la variable a été définie et que le répertoire a été modifié. La vérification montre ensuite que la variable n'est pas définie et que le répertoire n'est pas modifié. Qu'est-il arrivé? Les modifications ont été apportées dans un nouveau shell. Le shell actuel a généré un nouveau shell pour exécuter le script. Le script est exécuté dans le nouveau shell et toutes les modifications apportées à l'environnement sont prises en compte dans le nouveau shell. Une fois le script terminé, le nouveau shell est détruit. Toutes les modifications apportées à l'environnement dans le nouveau shell sont détruites avec le nouveau shell. Seul le texte de sortie est imprimé dans le shell actuel.

Maintenant, nous sources le fichier:

$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Vérifiez à nouveau l'environnement:

$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir

La variable FOO est définie et le répertoire de travail a été modifié.

La recherche du script ne crée pas de nouveau shell. Toutes les commandes sont exécutées dans le shell actuel et les modifications apportées à l'environnement prennent effet dans le shell actuel.

Notez que dans cet exemple simple, le résultat de l'exécution est identique à l'obtention du script. Ce n'est pas forcément toujours le cas.

Une autre manifestation

Considérez le script suivant pid.sh:

#!/bin/sh
echo $$

(la variable spéciale se $$développe en PID du processus en cours d'exécution du shell)

Commencez par imprimer le PID du shell actuel:

$ echo $$
25009

Source le script:

$ source pid.sh
25009

Exécutez le script, notez le PID:

$ ./pid.sh
25011

Source encore:

$ source pid.sh
25009

Exécutez à nouveau:

$ ./pid.sh
25013

Vous pouvez constater que le sourçage du script s'exécute dans le même processus, alors que l'exécution du script crée un nouveau processus à chaque fois. Ce nouveau processus est le nouveau shell créé pour l'exécution du script. La création du script ne crée pas de nouveau shell et le PID reste donc le même.

Sommaire

La recherche et l’exécution du script exécutent les commandes dans le script ligne par ligne, comme si vous les tapiez à la main, ligne par ligne.

Les différences sont:

  • Lorsque vous exécutez le script, vous ouvrez un nouveau shell, tapez les commandes dans le nouveau shell, copiez la sortie dans votre shell actuel, puis fermez le nouveau shell. Toute modification de l'environnement ne prendra effet que dans le nouveau shell et sera perdue une fois le nouveau shell fermé.
  • Lorsque vous sourcez le script, vous tapez les commandes dans votre shell actuel . Toute modification de l'environnement prendra effet et restera dans votre shell actuel.

Utilisez source si vous souhaitez que le script modifie l'environnement dans votre shell en cours d'exécution. utiliser exécuter autrement.


Voir également:

lesmana
la source
2
Une des utilisations du sourcing est de créer une forme rudimentaire de fichier de configuration pour vos scripts. Vous commencez par définir différentes variables avec des valeurs par défaut, puis source dans un fichier comme myscript.conf. Ce script source peut avoir des instructions d'affectation qui remplacent les valeurs souhaitées. Comme le script source ne commence pas par # / bin / bash, il n'est pas encouragé à l'exécuter directement.
LawrenceC
Donc, source est un peu comme si on l’exécutait dans une étendue globale et que l’exécution en créait une nouvelle. Cela peut-il être étendu à une fonction dans un script? pour exécuter une fonction (normalement) ou pour la "source"?
aliteralmind
2
Y a-t-il une différence entre utiliser source myscript.shet . myscript.sh?
Holloway
2
pratiquement pas de différence si vous utilisez bash. source est un alias à doter en bash.
Lesmana
1
J'adore quand les gens fournissent des exemples aussi élaborés que même les débutants en Linux comme moi peuvent comprendre. Merci!
Julius
21

L'exécution d'un script l'exécute dans un processus enfant distinct, c'est-à-dire qu'une instance distincte du shell est appelée pour traiter le script. Cela signifie que les variables d'environnement, etc., définies dans le script ne peuvent pas être mises à jour dans le shell parent (actuel).

La création d'un script signifie qu'il est analysé et exécuté par le shell actuel. C'est comme si vous avez tapé le contenu du script. Pour cette raison, le script recherché ne doit pas nécessairement être exécutable. Mais il doit être exécutable si vous l'exécutez bien sûr.

Si vous avez des arguments de position dans le shell actuel, ils ne sont pas modifiés.

Donc si j'ai un fichier a.shcontenant:

echo a $*

et je fais:

$ set `date`
$ source ./a.sh

Je reçois quelque chose comme:

a Fri Dec 11 07:34:17 PST 2009

Tandis que:

$ set `date`
$ ./a.sh

Donne moi:

a

J'espère que ça t'as aidé.

Alok
la source
5
Bien que cette réponse soit correcte à tous égards, je trouve cela très difficile à comprendre car elle est démontrée à l'aide d'un autre concept (réglage de paramètres de position), ce qui, à mon avis, est encore plus déroutant que la différence entre se procurer et exécuter lui-même.
Lesmana
9

L’approvisionnement est essentiellement la même chose que taper chaque ligne du script à l’invite de commande une par une ...

L'exécution démarre un nouveau processus, puis exécute chaque ligne du script, en modifiant uniquement l'environnement actuel en fonction de ce qu'il retourne.

John Weldon
la source
6

En plus de ce qui précède, exécuter le script en tant que ./myscriptnécessite l’autorisation d’exécution du fichier myscript, tandis que la recherche de sources n’exige aucune autorisation d’exécution. C'est pourquoi chmod +x myscriptn'est pas nécessaire avantsource myscript

abdos
la source
2
C'est vrai, mais si c'est un problème, vous pouvez toujours courir bash myscript.
Daniel Beck
5

Vous obtenez toutes les variables supplémentaires définies dans le script de sourcing.
Donc, si vous avez des configurations ou des définitions de fonctions, vous devez créer et ne pas exécuter. Les exécutions sont indépendantes de l'environnement des parents.

Arkaitz Jimenez
la source
3

Si je me souviens bien, l'exécution du script exécute le fichier exécutable dans la #!ligne avec le fichier de script sous forme d'argument (généralement, en démarrant un nouveau shell et en le localisant dans le nouveau shell, comme avec #!/bin/sh);
tandis que la recherche du script exécute chaque ligne de votre environnement shell actuel, ce qui est utile pour transformer votre shell actuel (par exemple, en fournissant un moyen de définir des fonctions de shell et d'exporter des variables d'environnement).

Shekhar
la source
2

sourceLa commande exécute le script fourni (l’autorisation exécutable n’est pas obligatoire ) dans l’ environnement actuel du shell, tandis que ./le script exécutable fourni est exécuté dans un nouveau shell.

Vérifiez également cette réponse par exemple: https://superuser.com/a/894748/432100

Harsh Vakharia
la source