La seule différence majeure est entre l'approvisionnement et l'exécution d'un script. source foo.shle source et tous les autres exemples que vous montrez sont en cours d'exécution. Plus en détail:
./file.sh
Cela exécutera un script appelé file.shqui se trouve dans le répertoire courant ( ./). Normalement, lorsque vous exécutez command, le shell recherchera dans les répertoires de votre $PATHfichier exécutable appelé command. Si vous donnez un chemin complet, tel que /usr/bin/commandou ./command, alors le $PATHest ignoré et ce fichier spécifique est exécuté.
../file.sh
C'est fondamentalement la même chose que ./file.shsauf qu'au lieu de chercher dans le répertoire courant file.sh, il cherche dans le répertoire parent ( ../).
sh file.sh
Cet équivalent à sh ./file.sh, comme ci-dessus, exécutera le script appelé file.shdans le répertoire courant. La différence est que vous l'exécutez explicitement avec le shshell. Sur les systèmes Ubuntu, c'est le cas dashet non bash. Habituellement, les scripts ont une ligne shebang qui donne le programme sous lequel ils doivent être exécutés. Les appeler avec un autre l'emporte. Par exemple:
$ cat foo.sh
#!/bin/bash
## The above is the shebang line, it points to bash
ps h -p $$ -o args='' | cut -f1 -d' ' ## This will print the name of the shell
Ce script affichera simplement le nom du shell utilisé pour l'exécuter. Voyons ce qu'il retourne lorsqu'il est appelé de différentes manières:
$ bash foo.sh
bash
$ sh foo.sh
sh
$ zsh foo.sh
zsh
Donc, appeler appeler un script avec shell scriptremplacera la ligne shebang (si elle est présente) et exécutera le script avec le shell que vous lui direz.
source file.sh ou . file.sh
Cela s'appelle, de façon assez surprenante, l' approvisionnement du script. Le mot source- clé est un alias de la .commande intégrée du shell . C'est une façon d'exécuter le script dans le shell courant. Normalement, lorsqu'un script est exécuté, il est exécuté dans son propre shell, différent de celui en cours. Pour illustrer:
$ cat foo.sh
#!/bin/bash
foo="Script"
echo "Foo (script) is $foo"
Maintenant, si je définis la variable foosur quelque chose d'autre dans le shell parent et que j'exécute ensuite le script, le script affichera une valeur différente de foo(car elle est également définie dans le script) mais la valeur de foodans le shell parent sera inchangée:
$ foo="Parent"
$ bash foo.sh
Foo (script) is Script ## This is the value from the script's shell
$ echo "$foo"
Parent ## The value in the parent shell is unchanged
Cependant, si je source le script au lieu de l'exécuter, il sera exécuté dans le même shell donc la valeur de foodans le parent sera modifiée:
$ source ./foo.sh
Foo (script) is Script ## The script's foo
$ echo "$foo"
Script ## Because the script was sourced,
## the value in the parent shell has changed
Ainsi, le sourcing est utilisé dans les rares cas où vous souhaitez qu'un script affecte le shell à partir duquel vous l'exécutez. Il est généralement utilisé pour définir des variables shell et les rendre disponibles une fois le script terminé.
Avec tout cela à l'esprit, la raison pour laquelle vous obtenez des réponses différentes est, tout d'abord, que votre script ne fait pas ce que vous pensez qu'il fait. Il compte le nombre de fois qui bashapparaît dans la sortie de ps. Ce n'est pas le nombre de terminaux ouverts , c'est le nombre de shells en cours d' exécution (en fait, ce n'est même pas ça, mais c'est une autre discussion). Pour clarifier, j'ai un peu simplifié votre script:
#!/bin/bash
logname=terdon
not=`ps -au$logname | grep -c bash`
echo "The number of shells opened by $logname is $not"
Et exécutez-le de différentes manières avec un seul terminal ouvert:
Lancement direct, ./foo.sh.
$ ./foo.sh
The number of shells opened by terdon is 1
Ici, vous utilisez la ligne shebang. Cela signifie que le script est exécuté directement par tout ce qui y est défini. Cela affecte la façon dont le script est affiché dans la sortie de ps. Au lieu d'être répertorié comme bash foo.sh, il ne sera affiché que foo.shce qui signifie que vous greple manquerez. Il y a en fait 3 instances bash en cours d'exécution: le processus parent, le bash exécutant le script et un autre qui exécute la pscommande . Ce dernier est important, le lancement d'une commande avec substitution de commande ( `command`ou $(command)) entraîne le lancement d'une copie du shell parent et l'exécution de la commande. Ici, cependant, aucun de ces éléments n'est affiché en raison de la façon dont il psaffiche sa sortie.
Lancement direct avec shell explicite (bash)
$ bash foo.sh
The number of shells opened by terdon is 3
Ici, parce que vous utilisez avec bash foo.sh, la sortie de pssera affichée bash foo.shet sera comptée. Donc, ici, nous avons le processus parent, l' bashexécution du script et le shell cloné (exécution de ps) tous affichés parce que maintenant psaffichera chacun d'eux parce que votre commande inclura le mot bash.
Lancement direct avec un autre shell ( sh)
$ sh foo.sh
The number of shells opened by terdon is 1
C'est différent parce que vous exécutez le script avec shet non bash. Par conséquent, la seule bashinstance est le shell parent où vous avez lancé votre script. Tous les autres obus mentionnés ci-dessus sont gérés par à la shplace.
Sourcing (soit par .ou source, même chose)
$ . ./foo.sh
The number of shells opened by terdon is 2
Comme je l'ai expliqué ci-dessus, l'approvisionnement d'un script le fait s'exécuter dans le même shell que le processus parent. Cependant, un sous-shell séparé est démarré pour lancer la pscommande et cela porte le total à deux.
Enfin, la bonne façon de compter les processus en cours n'est pas d'analyser psmais d'utiliser pgrep. Tous ces problèmes auraient été évités si vous veniez de courir
pgrep -cu terdon bash
Ainsi, une version de travail de votre script qui imprime toujours le bon numéro est (notez l'absence de substitution de commande):
#!/usr/bin/env bash
user="terdon"
printf "Open shells:"
pgrep -cu "$user" bash
Cela renverra 1 lors de la source et 2 (car un nouveau bash sera lancé pour exécuter le script) pour toutes les autres façons de lancer. Il renverra toujours 1 lors du lancement avec shpuisque le processus enfant ne l'est pas bash.