Pourquoi “cd” ne fonctionne-t-il pas dans un script shell?

43

Je veux juste écrire un script qui change mon répertoire .

Je mets les commandes ci-dessous dans le fichier /home/alex/pathABC

#!/bin/sh
cd /home/alex/Documents/A/B/C
echo HelloWorld

J'ai fait chmod +x pathABC.

Dans le terminal, pendant que /home/alexje suis, je cours ./pathABC, mais la sortie est juste HelloWorldet le répertoire actuel n’est pas changé.

Alors qu'est-ce qui ne va pas?

Mohammad Reza Rezwani
la source

Réponses:

74

Comme d'autres l'ont expliqué, le répertoire est modifié dans le processus enfant de votre script et non dans le processus terminal à partir duquel le script est appelé. Une fois que le processus enfant est mort, vous êtes de retour dans le terminal qui est laissé où il était.

Plusieurs alternatives:

1. Lien symbolique

Mettez un lien symbolique dans votre maison vers le long chemin auquel vous souhaitez accéder facilement

$ ln -s /home/alex/Documents/A/B/C ~/pathABC

puis accédez au répertoire avec:

$ cd ~/pathABC

2. alias

Mettez un alias dans votre ~ / .bashrc:

alias pathABC="cd /home/alex/Documents/A/B/C"

(à partir d' ici )

3. fonction

Créez une fonction qui modifie le répertoire, la fonction s'exécute dans le processus de votre terminal et peut ensuite changer de répertoire.

(à partir d' ici )

4. Évitez de courir comme un enfant

Source votre script au lieu de l'exécuter. La détermination de source (effectuée par .ou source) entraîne l'exécution du script dans le même shell au lieu de s'exécuter dans son propre sous-shell.

$ . ./pathABC

(d' ici et d' ici )

5. cd -able vars

Définissez l' cdable_varsoption dans votre ~/.bashrcet créez une variable d'environnement dans le répertoire:

shopt -s cdable_vars
export pathABC="/home/alex/Documents/A/B/C"

Ensuite, vous pouvez utiliser cd pathABC

(à partir d' ici )

Gauthier
la source
15
Maintenant je comprends l'utilisation de source! Je me suis toujours demandé pourquoi source .bashrcet pas bash .bashrc
moi
L'option 3 a très bien fonctionné. Je viens de définir une fonction go_to_wherever () {cd my / directory} au début de mon script. Appelé avant d'exécuter les opérations dans ce répertoire.
i2097i
> 5. vars cd -ables - n'est-ce pas cd $pathABC?
loxaxs
7

Lorsque vous exécutez un script dans un terminal, un processus enfant s'exécute. Dans ce programme enfant, votre script passera dans le répertoire spécifié. Mais dans le processus parent, c’est-à-dire que vous exécutez le script qui est toujours dans l’ancien chemin. OU simplement nous pouvons dire:

The scope of cd command is only for child process not parent

Tingrammer
la source
2
En plus de cela, @alex pour obtenir l’effet recherché, exécutez le script dans le processus parent en le recherchant: . pathABCou source pathABC.
Zwets
4

Vous faites une erreur de pensée. Bien que le shell actuel reste dans le même répertoire, le script a été déplacé dans le nouveau répertoire.

Vous pouvez le constater en créant un autre script dans le nouveau répertoire et en l'exécutant à partir de votre script, une fois le répertoire changé:

#!/bin/sh
cd /home/alex/Documents/A/B/C && ./another_script.sh # (if it is executable)

Le second script serait exécuté à partir du nouveau répertoire.

HelloWorld 

est juste la sortie du script.

Jacob Vlijm
la source
3
HelloWorld n'est pas "renvoyé" au shell parent, il est envoyé à la sortie standard
Mog
Cela pourrait être plus clair si vous exécutez simplement pwddans le nouveau répertoire, au lieu d’ajouter un tout nouveau script à la situation.
Wjandrea
0

Parce que hello world est juste une déclaration de trace, essayons ceci:

Créer un fichier de script bash cd.shcontenant:

#!/bin/bash
echo "/home/mike/Documents/A/B/C"
  • L' .shextension est une convention plus ancienne qui consiste à donner une extension aux noms de fichiers de script bash. C'est purement esthétique et généralement inutile. Cependant, dans ce cas, il est important de faire la différence avec la cdcommande principale .

Marquez le fichier de script bash comme exécutable en utilisant:

chmod a+x cd.sh

Maintenant, lancez le fichier:

$ cd $(./cd.sh)
bash: cd: /home/alex/Documents/A/B/C: No such file or directory
  • cd nous savons tous.
  • $(...) exécute la commande entre parenthèses et renvoie la sortie.
  • Si cd.shétait dans votre chemin, vous n'avez pas besoin de spécifier où il se trouve. Nous préfixons avec ./pour spécifier que la commande est dans le répertoire en cours.
  • La echosortie du cd.shscript est renvoyée au parent via le fichier $(...). Le parent (notre invite shell) utilise cette sortie et le transmet à la cdcommande Linux .

Comme d'autres l'ont mentionné, un processus enfant ne peut pas changer le répertoire du parent. C'est une façon pour l'enfant de dire au parent où aller après la fin du processus.

WinEunuuchs2Unix
la source
@wjandrea C'est ce que vous obtenez pour coder sur un téléphone! Je viens de rentrer à la maison, je vais arranger ça. Merci. Euh viens de vérifier et ça marche bien. Peut-être que c'est votre 14.04version que j'ai lue il y a environ une heure?
WinEunuuchs2Unix
Eh bien, vous avez totalement changé le script. Auparavant, ce n'était qu'une commande:, cd /home/mike/Documents/A/B/Cqui ne produisait aucune sortie. Maintenant, c'est echo "/home/mike/Documents/A/B/C"ce qui produit une sortie.
wjandrea
@wjandrea True, j'ai aussi totalement changé la façon d'appeler le script. Au lieu d'un simple, ./cd.shc'est maintenant, cd $(./cd.sh)mais l'objectif est de permettre à l'enfant de changer le répertoire actuel du parent. Oui, ce n'est pas conventionnel, mais c'est une autre façon de le faire que j'espère que les gens trouveront intéressante.
WinEunuuchs2Unix