Changer le répertoire actuel à partir d'un script Bash

190

Est-il possible de changer le répertoire courant à partir d'un script?

Je souhaite créer un utilitaire pour la navigation dans les répertoires dans Bash. J'ai créé un script de test qui ressemble à ce qui suit:

#!/bin/bash
cd /home/artemb

Lorsque j'exécute le script à partir du shell Bash, le répertoire actuel ne change pas. Est-il possible du tout de changer le répertoire courant du shell à partir d'un script?

artemb
la source
2
Juste une suggestion d'amélioration: si vous utilisez pushd(éventuellement redirigé vers >/dev/nullpour supprimer sa sortie) au lieu de cd, vous pouvez revenir plus tard au répertoire précédent avec popd.
mklement0

Réponses:

173

Vous devez convertir votre script en une fonction shell:

#!/bin/bash
#
# this script should not be run directly,
# instead you need to source it from your .bashrc,
# by adding this line:
#   . ~/bin/myprog.sh
#

function myprog() {
  A=$1
  B=$2
  echo "aaa ${A} bbb ${B} ccc"
  cd /proc
}

La raison en est que chaque processus a son propre répertoire courant, et lorsque vous exécutez un programme à partir du shell, il est exécuté dans un nouveau processus. Les standards "cd", "pushd" et "popd" sont intégrés à l'interpréteur du shell afin qu'ils affectent le processus du shell.

En faisant de votre programme une fonction shell, vous ajoutez votre propre commande in-process, puis tout changement de répertoire est reflété dans le processus shell.

Winden
la source
2
comment feriez-vous cela dans tcsh?
joedborg
4
+1. Une chose que j'ai remarquée était dans le fichier, nous devons définir la fonction avant de l'appeler. Cela pourrait aider quelqu'un d'aussi inexpérimenté que moi.
Bhushan
Quelle est la grande différence entre définir une fonction et créer un alias?
HelloGoodbye
1
Une fois que j'ai créé ce fichier myprog.sh et l'ai ajouté au fichier .bashrc, comment exécuter le script? Dois-je appeler ma fonction depuis un autre fichier shell ou directement depuis le shell? Il semble que cela ne fonctionne pas dans les deux sens ...
Andrea Silvestri
1
@AndreaSilvestri Déconnectez-vous et reconnectez-vous ou source .bashrc. L'ajouter à .bashrc ne fait rien tant que .bashrc n'est pas exécuté.
Jon Strayer
214

Lorsque vous démarrez votre script, un nouveau processus est créé qui n'hérite que de votre environnement. Quand ça se termine, ça se termine. Votre environnement actuel reste tel quel.

Au lieu de cela, vous pouvez démarrer votre script comme ceci:

. myscript.sh

Le .évaluera le script dans l'environnement actuel, il peut donc être modifié

Norbert Hartl
la source
4
+1 parce que vous avez raison. Bien que je doute sincèrement qu'il veuille trouver un script de changement de répertoire chaque fois qu'il en aura besoin. De plus, les .shextensions sont totalement eww. Ne les utilisez pas.
lhunath
1
Oui, il vaut généralement mieux ne pas l'utiliser de cette façon. La plupart du temps, vous êtes heureux que votre environnement actuel ne souffre pas. Mais ensuite, j'ai des scripts pour effectuer certaines tâches de configuration pour moi, y compris le passage au bon endroit, puis moi. eux aussi. Btw. .sh est bien sûr une question de style personnel. Je ne l'utiliserais probablement pas lors de l'installation de scripts à l'échelle du système. Mais dans mon ~ / bin je les utilise pour savoir ce qui est quoi :)
Norbert Hartl
11
@lhunath Pourquoi les extensions .sh sont-elles totalement eww?
Carl Pritchett
1
Extensions de nom de commande @CarlPritchett considérées comme nuisibles .
gniourf_gniourf
1
Pour moi, le raisonnement de cet article est faux. Il semble que le résultat ait été connu dès le départ, mais en trouver les raisons n'a pas été aussi simple. Donc je maintiens mon point de vue, c'est une question de style personnel, rien d'autre.
Norbert Hartl
55

À la lumière de l'illisibilité et de la trop grande complexité des réponses, je pense que c'est ce que le demandeur devrait faire

  1. ajouter ce script au PATH
  2. exécutez le script en tant que . scriptname

Le .(point) garantira que le script n'est pas exécuté dans un shell enfant.

Steven Penny
la source
38

En réunissant ce qui précède, vous pouvez créer un alias

alias your_cmd=". your_cmd"

si vous ne voulez pas écrire le premier "." chaque fois que vous souhaitez générer votre script dans l'environnement shell, ou si vous ne voulez tout simplement pas vous souvenir que cela doit être fait pour que le script fonctionne correctement.

MergerMan
la source
Cela restera-t-il persistant lors des redémarrages?
SDsolar
1
@SDsolar Vous devez l'ajouter à votre fichier ~ / .bashrc pour le rendre persistant. Fonctionne comme un charme pour moi.
Rafał G.
Peut être mis dans ~ / .bash_aliases
Champ
@Champ ~/.bash_aliasesn'est pas toujours source lors du lancement de Bash.
Mateusz Piotrowski
31

Si vous utilisez bash, vous pouvez essayer alias:

dans le fichier .bashrc ajoutez cette ligne:

alias p='cd /home/serdar/my_new_folder/path/'

lorsque vous écrivez "p" sur la ligne de commande, cela changera de répertoire.

Akarca
la source
1
+1 pour alias. La fonction shell est intéressante mais l'OP a demandé un simple nav avec cd. Je suppose que la plupart des gens ont besoin d'un script comme celui-ci pour naviguer dans les branches du code source et que cet alias est suffisant
Brad Dre
19

Si vous exécutez un script bash, il fonctionnera sur son environnement actuel ou sur ceux de ses enfants, jamais sur le parent.

Si l'objectif est d'exécuter votre commande: goto.sh / home / test, travaillez alors de manière interactive dans / home / test, une façon consiste à exécuter un sous-shell interactif bash dans votre script:

#!/bin/bash
cd $1
exec bash

De cette façon, vous serez dans / home / test jusqu'à ce que vous quittiez (quitter ou Ctrl + C) de ce shell.

philippe lhardy
la source
Je pensais que cela résoudrait le problème d'un script shell que j'exécutais, mais à la place, il démarre le shell et oublie ce que je voulais.
vwvan
14

Avec pushd, le répertoire courant est poussé sur la pile de répertoires et il est changé dans le répertoire donné, popd récupère le répertoire au-dessus de la pile et le change ensuite.

pushd ../new/dir > /dev/null
# do something in ../new/dir
popd > /dev/null
Seb
la source
2
Cela répond à ma question - déployer activement cette solution dans un script d'initialisation S3 et cela fonctionne parfaitement bien. Merci @seb.
19h le
5

Allez simplement à

yourusername/.bashrc (or yourusername/.bash_profile on MAC) by an editor

et ajoutez ce code à côté de la dernière ligne:

alias yourcommand="cd /the_path_you_wish"

Puis quittez l'éditeur.

Tapez ensuite:

source ~/.bashrc or source ~/.bash_profile on MAC.

maintenant vous pouvez utiliser: votre commande dans le terminal

ThangTD
la source
3

Fondamentalement, nous avons l'habitude cd..de revenir de chaque répertoire. J'ai pensé à vous faciliter la tâche en donnant le nombre de répertoires avec lesquels vous devez revenir à la fois. Vous pouvez l'implémenter à l'aide d'un fichier de script distinct à l'aide de la commande alias. Par exemple:

code.sh

#!/bin/sh
 _backfunc(){
 if [ "$1" -eq 1 ]; then
  cd ..
 elif [ "$1" -eq 2 ]; then
  cd ../..
 elif [ "$1" -eq 3 ]; then
  cd ../../..
 elif [ "$1" -eq 4 ]; then
  cd ../../../..
 elif ["$1" -eq 10]; then
  cd /home/arun/Documents/work
 fi
 }
alias back='_backfunc'   

Après avoir utilisé source code.shdans le shell actuel, vous pouvez utiliser:

$back 2 

pour revenir à deux pas du répertoire courant. Expliqué en détail ici . Il est également expliqué là-bas comment mettre le code dans ~ / .bashrc pour que chaque nouveau shell ouvert ait automatiquement cette nouvelle commande d'alias. Vous pouvez ajouter une nouvelle commande pour accéder à des répertoires spécifiques en modifiant le code en ajoutant if conditionsdes arguments plus nombreux et différents. Vous pouvez également extraire le code de git ici .

Arun Chettoor
la source
Belle solution, pour ne jamais gâcher votre profil bash :)
J4cK
0

Cette approche est plus simple pour moi.

Supposons que sur un iMac personnel où vous êtes un administrateur, sous le répertoire par défaut lorsqu'une fenêtre de commande est ouverte, / Users / jdoe, ce sera le répertoire où aller: /Users/jdoe/Desktop/Mongo/db.3.2.1 /poubelle.

Voici les étapes qui peuvent faire le travail:

  1. vi mongobin, dans lequel je suis entré: cd /Users/jdoe/Desktop/Mongo/db.3.2.1/bincomme première ligne.
  2. chmod 755 mongobin
  3. source mongobin
  4. pwd

Voila!

Daniel C. Deng
la source
0

J'ai également créé un utilitaire appelé goat que vous pouvez utiliser pour une navigation plus facile.

Vous pouvez afficher le code source sur GitHub .

Depuis la v2.3.1, l' aperçu de l' utilisation ressemble à ceci:

# Create a link (h4xdir) to a directory:
goat h4xdir ~/Documents/dev

# Follow a link to change a directory:
cd h4xdir

# Follow a link (and don't stop there!):
cd h4xdir/awesome-project

# Go up the filesystem tree with '...' (same as `cd ../../`):
cd ...

# List all your links:
goat list

# Delete a link (or more):
goat delete h4xdir lojban

# Delete all the links which point to directories with the given prefix:
goat deleteprefix $HOME/Documents

# Delete all saved links:
goat nuke

# Delete broken links:
goat fix
Mateusz Piotrowski
la source
0

J'aime faire la même chose pour différents projets sans déclencher un nouveau shell.

Dans ton cas:

cd /home/artemb

Enregistrez le_script sous:

echo cd /home/artemb

Puis lancez-le avec:

\`./the_script\`

Ensuite, vous accédez au répertoire en utilisant le même shell.

DrGamma
la source
0

Ajoutez ci-dessous la ligne cd dans votre shellscript ceci:

exec $SHELL
Alberto Corella
la source
0

Déclarez votre chemin:

PATH='/home/artemb'     
cd ${PATH}
m_sam
la source
0

Il suffit d'écrire PWDet de l'exporter dans votre script, et le changement persistera.

export PWD=/your/desired/directory
Samha '
la source