web-dev-qa-db-fra.com

Pourquoi "cd" ne fonctionne-t-il pas dans un script Shell?

J'essaie d'écrire un petit script pour changer le répertoire actuel dans mon répertoire de projet:

#!/bin/bash
cd /home/tree/projects/Java

J'ai enregistré ce fichier en tant que proj, ajouté une autorisation d'exécution avec chmod et l'a copié dans /usr/bin. Quand je l'appelle par: proj, cela ne fait rien. Qu'est-ce que je fais mal?

656
ashokgelal

Les scripts shell sont exécutés dans un sous-shell et chaque sous-shell a son propre concept de ce que le répertoire actuel est. La cd réussit, mais dès que le sous-shell se ferme, vous revenez dans le shell interactif et rien n'y a jamais changé.

Une façon de contourner ce problème consiste à utiliser un alias à la place:

alias proj="cd /home/tree/projects/Java"
555
Greg Hewgill

Tu ne fais rien de mal! Vous avez modifié le répertoire, mais uniquement dans le sous-shell qui exécute le script.

Vous pouvez exécuter le script dans votre processus actuel avec la commande "dot":

. proj

Mais je préférerais que la proposition de Greg utilise un alias dans ce cas simple.

438
Adam Liss

La cd de votre script techniquement travaillait car elle modifiait le répertoire du Shell qui exécutait le script, mais il s’agissait d’un processus distinct créé à partir de votre Shell interactif.

Un moyen compatible avec Posix de résoudre ce problème consiste à définir un procédure Shell plutôt qu'un script de commande invoqué par Shell .

jhome () {
  cd /home/tree/projects/Java
}

Vous pouvez simplement le saisir ou le placer dans l'un des différents fichiers de démarrage de Shell.

205
DigitalRoss

La cd est effectuée dans le shell du script. Lorsque le script se termine, ce shell se ferme et vous restez dans le répertoire que vous étiez. "Source" le script, ne l'exécutez pas. Au lieu de:

./myscript.sh

faire

. ./myscript.sh

(Remarquez le point et l'espace avant le nom du script.)

135
Tzachi.e

Pour créer un script bash qui sera cd dans un répertoire de sélection:

Créer le fichier de script

 #!/bin/sh 
 # fichier: /scripts/cdjava
#
cd /home/askgelal/projects/Java

Créez ensuite un alias dans votre fichier de démarrage.

 #!/bin/sh 
 # fichier /scripts/mastercode.sh
#
alias cdjava = '. /scripts/cdjava'

  • J'ai créé un fichier de démarrage dans lequel je vide tous mes alias et fonctions personnalisées .
  • Ensuite, je source ce fichier dans mon .bashrc pour l’avoir défini à chaque démarrage .

Par exemple, créez un fichier d'alias/fonctions maître: /scripts/mastercode.sh
(Mettez l'alias dans ce fichier.)

Puis à la fin de ton .bashrc fichier:

 source /scripts/mastercode.sh



Maintenant, il est facile de vous connecter à votre répertoire Java, tapez simplement cdjava et vous y êtes.

90
Matt Thomas

L'idée de Jeremy Ruten d'utiliser un lien symbolique a déclenché une pensée qui n'a croisé aucune autre réponse. Utilisation:

CDPATH=:$HOME/projects

Le côlon principal est important; cela signifie que s'il y a un répertoire 'dir' dans le répertoire actuel, alors 'cd dir' changera en celui-ci, plutôt que de sauter ailleurs. Avec la valeur définie comme indiqué, vous pouvez faire:

cd Java

et, s'il n'y a pas de sous-répertoire appelé Java dans le répertoire actuel, cela vous mènera directement à $ HOME/projects/Java - pas d'alias, pas de scripts, pas d'execs douteux ni de commandes point.

Mon $ HOME est/Users/jleffler; mon $ CDPATH est:

:/Users/jleffler:/Users/jleffler/mail:/Users/jleffler/src:/Users/jleffler/src/Perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work
36
Jonathan Leffler

Vous pouvez utiliser . pour exécuter un script dans l'environnement Shell actuel:

. script_name

ou bien son alias plus lisible mais spécifique à Shell source:

source script_name

Cela évite le sous-shell et permet à toutes les variables ou fonctions intégrées (y compris cd) d’affecter le Shell en cours.

33
Astha

J'ai obtenu mon code en utilisant. <your file name>

./<your file name> dose ne fonctionne pas car il ne change pas votre répertoire dans le terminal, il modifie simplement le répertoire spécifique à ce script. 

Voici mon programme

#!/bin/bash 
echo "Taking you to Eclipse's workspace."
cd /Developer/Java/workspace

Voici mon terminal 

nova:~ Kael$ 
nova:~ Kael$ . workspace.sh
Taking you to eclipe's workspace.
nova:workspace Kael$ 
25
kaelhop

Utilisez exec bash à la fin

Un script bash opère sur son environnement actuel ou sur celui de son enfants, mais jamais sur son environnement parent.

Cependant, cette question est souvent posée car on veut être laissé à une invite bash dans un certain répertoire après l'exécution d'un script bash depuis un autre répertoire.

Si tel est le cas, exécutez simplement une instance de l'enfant bash à la fin du script:

#!/bin/bash
cd /home/tree/projects/Java
exec bash
18
Serge Stroobandt

tout simplement courir:

cd /home/xxx/yyy && command_you_want
17
warhansen

Lorsque vous lancez un script shell, il exécute une instance new de ce shell (/bin/bash). Ainsi, votre script déclenche simplement un shell, modifie le répertoire et quitte. En d'autres termes, cd (et d'autres commandes similaires) au sein d'un script de shell n'a aucune incidence sur l'accès au shell à partir duquel ils ont été lancés.

11
Daniel Spiewak

Sur mon cas particulier, j'ai eu besoin de trop de fois pour changer pour le même répertoire. Alors sur mon .bashrc (j’utilise Ubuntu) j’ai ajouté le 

1 -

$ nano ~./bashrc

 function switchp
 {
    cd /home/tree/projects/$1
 }

2- 

$ source ~/.bashrc

3 - 

$ switchp Java

Directement cela fera: cd/home/arbre/projets/Java

J'espère que cela pourra aider!

9
workdreamer

Vous pouvez faire ce qui suit:

#!/bin/bash
cd /your/project/directory
# start another Shell and replacing the current
exec /bin/bash

EDIT: Cela pourrait également être «pointillé», pour empêcher la création de shells ultérieurs.

Exemple:

. ./previous_script  (with or without the first line)
8
Thevs

Vous pouvez combiner un alias et un script,

alias proj="cd \`/usr/bin/proj !*\`"

à condition que le script répète le chemin de destination. Notez que ce sont des backticks entourant le nom du script.

Par exemple, votre script pourrait être

#!/bin/bash
echo /home/askgelal/projects/Java/$1

L'avantage de cette technique est que le script peut prendre un nombre quelconque de paramètres de ligne de commande et émettre différentes destinations calculées par une logique éventuellement complexe.

7
J. A. Faucett

Il ne change que le répertoire du script lui-même, alors que votre répertoire actuel reste le même.

Vous voudrez peut-être utiliser un lien symbolique à la place. Il vous permet de créer un "raccourci" vers un fichier ou un répertoire, de sorte que vous ne devez taper que quelque chose comme cd my-project.

7
Jeremy Ruten
5
Gene T

Vous pouvez combiner les approches des alias et des points d'Adam & Greg pour créer quelque chose qui peut être plus dynamique ...

alias project=". project"

L'exécution de l'alias de projet maintenant exécutera le script de projet dans le shell actuel, par opposition au sous-shell. 

5
mogga

Dans votre fichier ~/.bash_profile. ajouter la fonction suivante

move_me() {
    cd ~/path/to/dest
}

Redémarrez le terminal et vous pouvez taper

move_me 

et vous serez déplacé vers le dossier de destination.

3
mihai.ciorobea

Bien que la recherche du script que vous souhaitez exécuter soit une solution, vous devez savoir que ce script peut alors modifier directement l'environnement de votre Shell actuel. En outre, il n'est plus possible de passer des arguments.

Une autre façon de faire consiste à implémenter votre script en tant que fonction dans bash.

function cdbm() {
  cd whereever_you_want_to_go
  echo "Arguments to the functions were $1, $2, ..."
}

Cette technique est utilisée par autojump: http://github.com/joelthelion/autojump/wiki pour vous permettre d’apprendre les signets du répertoire Shell.

3
thomasd

Cela devrait faire ce que vous voulez. Accédez au répertoire qui vous intéresse (à partir du script), puis créez un nouveau shell bash.

#!/bin/bash

# saved as mov_dir.sh
cd ~/mt/v3/rt_linux-rt-tools/
bash

Si vous exécutez ceci, cela vous mènera au répertoire qui vous intéresse et lorsque vous le quitterez, cela vous ramènera à l'emplacement d'origine.

root@intel-corei7-64:~# ./mov_dir.sh

root@intel-corei7-64:~/mt/v3/rt_linux-rt-tools# exit
root@intel-corei7-64:~#

Cela vous amènera même à revenir à votre répertoire d'origine lorsque vous quitterez (CTRL+d)

3
jithu83

Vous pouvez utiliser l'opérateur &&:

cd myDirectory && ls

3
Jack Bauer

Peu de temps après, mais j'ai fait ce qui suit:

créer un fichier appelé cas

collez le texte suivant dans le fichier:

#!/bin/sh

cd /home/"$1"

sauvegardez-le et ensuite:

chmod +x case

J'ai aussi créé un alias dans mon .bashrc:

alias disk='cd /home/; . case'

maintenant, quand je tape:

case 12345

essentiellement, je tape:

cd /home/12345

Vous pouvez taper n'importe quel dossier après 'cas':

case 12

case 15

case 17

qui est comme taper:

cd /home/12

cd /home/15

cd /home/17

respectivement

Dans mon cas, le chemin est beaucoup plus long - ces gars-là l'ont résumé avec les informations plus tôt.

2
chris

Vous pouvez créer une fonction comme ci-dessous dans votre .bash_profile et cela fonctionnera sans problème.

La fonction suivante prend un paramètre optionnel qui est un projet . Par exemple, vous pouvez simplement lancer

cdproj

ou

cdproj project_name

Voici la définition de la fonction.

cdproj(){
    dir=/Users/yourname/projects
    if [ "$1" ]; then
      cd "${dir}/${1}"
    else
      cd "${dir}"
    fi
}

N'oubliez pas de source votre .bash_profile

1
Krish

Vous n'avez besoin d'aucun script, définissez uniquement l'option correcte et créez une variable d'environnement.

shopt -s cdable_vars

dans votre ~/.bashrc permet de cd au contenu des variables d'environnement.

Créez une telle variable d'environnement:

export myjava="/home/tree/projects/Java"

et vous pouvez utiliser:

cd myjava

Autres alternatives .

0
Gauthier

Si vous utilisez fish comme shell, la meilleure solution consiste à créer une fonction. Par exemple, à partir de la question d'origine, vous pouvez copier les 4 lignes ci-dessous et les coller dans la ligne de commande de votre poisson:

function proj
   cd /home/tree/projects/Java
end
funcsave proj

Cela va créer la fonction et l'enregistrer pour une utilisation ultérieure. Si votre projet change, répétez simplement le processus en utilisant le nouveau chemin.

Si vous préférez, vous pouvez ajouter manuellement le fichier de fonction en procédant comme suit:

nano ~/.config/fish/functions/proj.fish

et entrez le texte:

function proj
   cd /home/tree/projects/Java
end

et enfin appuyez sur ctrl + x pour quitter et y suivi de retour pour enregistrer vos modifications.

(NOTE: la première méthode d'utilisation de funcsave crée le fichier proj.fish pour vous).

0
Lane Roathe

J'ai un simple script bash appelé p pour gérer le changement de répertoire
github.com/godzilla/bash-stuff
il suffit de placer le script dans votre répertoire bin local (/ usr/local/bin)
et met

alias p='. p'

dans votre .bashrc 

0
godzilla

Utilisation des fonctions de profil Bash:

Une des caractéristiques du profil bash consiste à stocker des fonctions personnalisées pouvant être exécutées dans le terminal ou dans des scripts bash de la même manière que vous exécutez application/commandes. Cela pourrait également être utilisé comme raccourci pour les commandes longues. 

Pour que votre fonction soit plus efficace, vous devrez la copier au bout de plusieurs fichiers.

/home/user/.bashrc
/home/user/.bash_profile
/root/.bashrc
/root/.bash_profile

Vous pouvez Sudo kwrite /home/user/.bashrc /home/user/.bash_profile /root/.bashrc /root/.bash_profile éditer/créer ces fichiers rapidement

Exemple de script

Créer un raccourci vers cd .. avec cdd

cdd() {
  cd ..
}

ls raccourci

ll() {
  ls -l -h
}

ls raccourci

lll() {
  ls -l -h -a
}

Comment :

Copiez votre fonction à la fin de vos fichiers et redémarrez votre terminal. Vous pouvez ensuite exécuter cdd ou quelle que soit la fonction que vous avez écrite.

0
intika

Notez la discussion Comment définir le répertoire de travail du processus parent?

Il contient des réponses hackish, par exemple: __. https://stackoverflow.com/a/2375174/755804 (modification du répertoire du processus parent via gdb, ne le faites pas) et https: // stackoverflow .com/a/51985735/755804 (La commande tailcd qui injecte cd dirname dans le flux d'entrée du processus parent; dans l'idéal, elle devrait faire partie de bash plutôt que d'un piratage)

0