Quelle est la différence entre un source ('.' Ou 'source') et l’exécution d’un fichier en bash?

76

Quelle est la différence entre l'exécution d'un script comme celui-ci:

./test.sh

et en exécutant un script comme celui-ci:

. test.sh?

J'ai essayé un script simple de deux lignes pour voir si je pouvais trouver s'il y avait une différence:

#!/bin/bash
ls

Mais les deux . test.shet ont ./test.shretourné la même information.

Natan
la source
Toutes mes excuses s'il s'agit d'un doublon. Après une enquête plus approfondie, j'ai trouvé des pages contenant des informations pertinentes en recherchant "bash dot" au lieu de "bash.".
Natan
3
Tout comme ce test.shn'est pas la même chose que ./test.sh(le premier invoque une PATHrecherche), il en va de même . test.shet . ./test.shdifférent de la même manière (le premier invoque une PATHrecherche). De nombreux shells semblent inclure implicitement .à la fin d' PATHune .recherche de chemin d'accès, mais ce comportement n'est pas standard. Ainsi, il est plus juste de comparer test.shvs . test.shet ./test.shvs . ./test.sh.
jw013

Réponses:

83

./test.shfonctionne test.shcomme un programme séparé. Il peut arriver que ce soit un script bash, si le fichier test.shcommence par #!/bin/bash. Mais cela pourrait être tout à fait autre chose.

. ./test.shexécute le code du fichier test.shdans l'instance en cours d'exécution de bash. Cela fonctionne comme si le fichier de contenu test.shavait été inclus textuellement au lieu de la . ./test.shligne. (Presque: il y a quelques détails qui diffèrent, tels que la valeur $BASH_LINENOet le comportement de la commande returnintégrée.)

source ./test.shest identique à . ./test.shin bash (dans d'autres shells, sourcepeut être légèrement différent ou ne pas exister du tout; .pour l'inclure, il s'agit de la norme POSIX).

La différence la plus visible entre l’exécution d’un script distinct ./test.shet l’inclusion d’un script avec l’ .intégré réside dans le fait que si le test.shscript définit certaines variables d’environnement, avec un processus séparé, seul l’environnement du processus enfant est défini, tandis que lorsqu’un script est inclus, l’environnement du processus shell unique est défini. Si vous ajoutez une ligne foo=bardans test.shet echo $fooà la fin du script d'appel, vous verrez la différence:

$ cat test.sh
#!/bin/sh
foo=bar
$ ./test.sh
$ echo $foo

$ . ./test.sh
$ echo $foo
bar
Gilles, arrête de faire le mal
la source
17
Ajouter echo $$au script montrera également la différence. La $$variable contient le PID du shell actuel.
1
Un autre scénario d'utilisation consiste à utiliser l' . ./test.shappel provenant d'un autre script de shell pour utiliser les fonctions décrites dans test.sh. Je veux dire, ce ne sont pas seulement des variables que vous pouvez définir, vous pouvez également créer de nouvelles fonctions de cette manière, qui sont ensuite appelables à partir de bash, ou d'un autre script. . /usr/libexec/company/tools; custom_command "variable"
Rqomey
9

L'exécution initiale d'un script l'exécute en tant que processus enfant. La recherche de source (la seconde façon), en revanche, exécute le script comme si vous aviez entré toutes ses commandes dans le shell actuel. Si le script définit une variable, il le restera. Si le script se ferme, votre session se fermera. Voir help .pour la documentation.

choroba
la source
3

Une autre chose que je remarque est que si vous avez un alias comme celui-ci:

# add into .bashrc_aliases
alias ls='ls -lht'

Avec ./test.shvous obtiendrez une lssortie normale (et un PID différent de celui du shell actuel):

auraham@pandora:~/iso$ ./test.sh 
dsl-4.4.10.iso  test.sh
3136 # PID

Avec . test.shou . ./test.shvous obtiendrez une sortie plus détaillée (et le même PID que le shell actuel):

auraham@pandora:~/iso$ echo $$
2767 # shell PID

auraham@pandora:~/iso$ . test.sh 
total 50M
drwxrwxr-x  2 auraham auraham 4.0K Jul 30 15:41 .
-rwxrwxr-x  1 auraham auraham   32 Jul 30 15:41 test.sh
drwxr-xr-x 50 auraham auraham 4.0K Jul 30 15:30 ..
-rw-rw-r--  1 auraham auraham  50M Jul 28 17:24 dsl-4.4.10.iso
2767 # PID
Auraham
la source
Vous pouvez inclure ceci dans .bashrc if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi Ensuite, mettez vos alias dans .bash_aliases.
auraham
Bien sûr, mais vous ne devez toujours pas utiliser le aliasmot clé? (Peut-être que c'est juste une erreur dans votre message - sur la ligne 3?)
Emanuel Berg
totalement correct, mon erreur. Merci @EmanuelBerg
auraham
-1

L'utilisation principale pour moi source(ou .) est fonctions bash .

J'ai des scripts avec beaucoup de fonctions et je les exécute tous avec mon .bashrc. Les fonctions "deviennent" des commandes que j'utilise souvent.

Willian Paixao
la source
J'ai essayé les trois méthodes dans .bashrc - source, la position absolue du script et le nom de la commande (placer le script dans un dossier PATH) - et les trois méthodes ont fonctionné.
Emanuel Berg