Appel d'un script avec ./bla.sh vs. bla.sh

11

Quelqu'un peut-il m'expliquer ce que fait le shell dans les deux exemples A) et B) ci-dessous? Il se comporte évidemment différemment, mais je ne peux pas comprendre pourquoi la sortie est différente.

Exemple:
Ayons un script dans notre répertoire actuel nommé bla.shavec une seule commande:
echo ${0##/*} hello

A)
Commencé comme: ./bla.sh
donne:./bla.sh hello

B)
Commencé comme: . bla.sh
donne:-bash hello

Puisque j'utilise ceci dans un script, la deuxième sortie (à cause du "-" devant le -bash) tue la commande. Bien sûr, un simple --avant l' ${...}aide, mais j'aimerais comprendre ce qui cause la sortie en premier lieu.
J'adore bash. Et vi [m]. Mais je m'égare…

Loup
la source

Réponses:

22
./bla.sh

Ici, la commande est ./bla.sh. Cela fait que le shell recherche un exécutable nommé bla.shdans le répertoire courant, puis demande au noyau de l'exécuter comme un programme normal, dans un processus distinct du shell. (Peu importe si bla.shc'est un bashscript, un perlou pythonun, ou un binaire compilé.)


. bla.sh

Ici, la commande est .(aka source), une commande intégrée de votre shell. Cela fait que le shell recherche un fichier nommé bla.shdans le chemin du système ($ PATH) et interprète le contenu comme s'il avait été tapé par vous; tout cela se fait dans le même processus que le shell lui-même (et peut donc affecter l'état interne du shell).

Bien sûr, cela ne fonctionne que lorsque bla.shcontient des commandes pour le bashshell (si c'est celle que vous utilisez actuellement), cela ne fonctionnera pas pour les perlscripts ou autre chose.

(Ceci est expliqué dans help .et help sourceaussi.)


Comme .et ./sont des choses complètement différentes (une commande vs une partie d'un chemin), elles peuvent être combinées, bien sûr - en utilisant . ./bla.shcela "source" un fichier bla.shdans le répertoire courant.


Il est généralement préférable d'utiliser la ./bla.shméthode. Uniquement ~/.bashrc, ~/.profileet ces fichiers proviennent généralement, car ils sont censés modifier l'environnement actuel.

user1686
la source
3
De plus, si vous changez l'environnement bash dans bla.sh, ces changements sont pris en compte par la suite. bla.sh mais pas après ./bla.sh. Ceci est dû au fait . bla.sh s'exécute dans le contexte de la bash actuelle tandis que ./bla.sh s'exécute en tant que sous-processus.
mouviciel
1
Voir aussi mywiki.wooledge.org/BashFAQ/060 pour quelques exemples. Notez que sourcec'est un alias bash pour ., pas le contraire et sourcene fonctionnera pas dans d'autres shells.
mrucci
7

./<cmd>exécutera le <cmd>programme qui réside dans le répertoire courant dans un nouveau processus (fourchu). Il doit être exécutable. Et aussi lisible, il commence par #!.

. <cmd>fera exécuter à votre shell actuel le script shell <cmd>qui réside dans votre $PATHrépertoire ou dans le répertoire courant du processus shell actuel . Il doit être lisible. Il s'agit d'un alias pour la commande shell source.

kmkaplan
la source
-1 . <cmd>recherchera le programme dans $PATHet s'il n'est pas trouvé ALORS il cherchera dans le répertoire courant.
dogbane
@dogbane Oui, j'ai corrigé cela.
kmkaplan
FWIW, tous les shells ne rechercheront pas dans cwd des sripts d'origine. zsh (au moins avec la config que j'ai) nécessite. ./cmd
bstpierre
1
@bstpierre Cela semble être un terrain mouvant. La référence POSIX que j'ai indique que «le shell doit utiliser le chemin de recherche spécifié par PATH» et «Certaines implémentations plus anciennes ont recherché le fichier dans le répertoire courant, même si la valeur de PATH l'a interdit.»
kmkaplan
1

./cmd utilise un chemin explicite ( ./- dir actuel) vers l'exécutable. Et il n'est pas nécessaire que cela commence par #!.

. cmd- (aka source) - commande bash intégrée. Une différence visible de l'exécution à travers sourceest qu'il peut définir / modifier la variable d'environnement du shell actuel.

Leonid Volnitsky
la source
plus précisément, sourceest un alias bash uniquement .(qui est standard)
user1686
Tu as raison. Fixé.
Leonid Volnitsky