Quelle est la différence entre «source x», «. x "et" ./x "dans Bash?

11

J'ai une source bash run.shcomme suit,

#!/bin/bash
if [ $# -ne 1 ]; then
    exit
fi
...

quand je l'exécute de deux manières, il y a des comportements différents. La première façon est,

source run.sh

Il fermera le terminal après exécution. La deuxième façon est,

./run.sh

cela terminera simplement l'exécution du script et restera sur le terminal. Je demande s'il y a une commande pour quitter un script bash pour les deux source run.shet l' ./run.shexécution. J'ai essayé returnaussi, ce qui ne fonctionne pas bien en cours d' ./run.shexécution.

Plus généralement, je suis intéressé par la raison pour laquelle cela se produit, et quelle est la différence entre l'utilisation de "source" et "." pour l'exécution de script?

Richard
la source

Réponses:

16

Avant de répondre, je pense que certaines clarifications sont nécessaires. Analysons les trois lignes suivantes:

source run.sh
. run.sh
./run.sh

Les deux premières lignes sont exactement identiques: .est en fait un alias pour source. Qu'est source- ce que c'est d'exécuter le script shell dans le contexte actuel, d'où un appel à exitpour quitter le shell.

La troisième ligne (qui est celle qui vous déroute) n'a cependant rien à voir avec les autres lignes. ./run.shest juste un chemin d'accès et est identique à (par exemple) /home/user/run.shou /usr/bin/something. Souvenez-vous toujours que les commandes dans le shell sont séparées par un espace. Donc, dans ce cas, la commande ne l'est pas ., mais elle l'est ./run.sh: cela signifie qu'un sous-shell sera exécuté et que l' exiteffet n'aura d'effet que sur le sous-shell.

Andrea Corbellini
la source
5

Trois façons:

Vous pouvez inclure le script dans une fonction et utiliser uniquement return.

#!/usr/bin/env bash
main() {
    ...
    return 1
    ...
}
main "$@"

Vous pouvez tester si le script provient d'un shell interactif.

if [[ $- = *i* ]]; then
    return 1
else
    exit 1
fi

Vous pouvez essayer de revenir et, en cas d'échec, quitter.

return 1 2>/dev/null || exit 1
geirha
la source
Des indices sur le fonctionnement de l'incantation magique $- = *i* ?
deadbeef404
@ deadbeef404 Le paramètre spécial -contient les drapeaux d'options actuellement actifs. Le test vérifie si le -idrapeau est actif. Voir gnu.org/software/bash/manual/html_node/Special-Parameters.html
geirha
1

Considérez la commande «source» comme dans l'instruction «include». Il prend le contenu de l'argument et l'exécute comme s'il avait été exécuté directement. Dans ce cas, votre commande est «source» avec un argument «run.sh» et run.sh est exécuté exactement comme si vous aviez tapé le contenu de run.sh dans votre ligne de commande.

Lorsque vous exécutez './run.sh', './run.sh' est votre commande et elle n'a aucun argument. Comme ce fichier est en texte brut et non binaire, votre shell recherche un interprète au niveau du shebang ('#!' Sur la première ligne) et trouve '/ bin / bash'. Votre shell démarre alors une nouvelle instance de bash et le contenu de run.sh est exécuté à l'intérieur de cette nouvelle instance.

Dans le premier cas, lorsque bash atteint la commande «exit», il est exécuté exactement comme si vous l'aviez tapé dans la ligne de commande. Dans les deuxièmes instances, il est exécuté dans le processus bash que votre shell a démarré, donc seule cette instance de bash reçoit une commande 'exit'.

Lorsque vous tapez une ligne dans bash, tout ce qui précède le premier espace est traité comme une commande et tout ce qui suit est traité comme des arguments. La commande '.' est un alias de «source». Quand tu cours '. run.sh 'le'. ' est une commande à part entière car elle est séparée de ses arguments par un espace. Lorsque vous exécutez './run.sh', votre commande est './run.sh' et '.' fait partie du chemin d'accès relatif à run.sh avec le '.' représentant votre dossier actuel.

fume2345
la source
Si vous êtes un programmeur C / C ++ qui cherche à s'améliorer avec les scripts shell / bash, c'est la réponse parfaite.
Justin