est-il possible de changer le répertoire de travail du shell parent par programmation?

8

Je veux écrire du code pour me permettre de passer à certains répertoires auxquels je vais habituellement. Disons que ce programme est mycdet /a/very/long/path/nameest le répertoire dans lequel je veux aller.

Je peux donc simplement taper mycd 2au lieu de cd /a/very/long/path/name. Ici, je suppose que mycdsait 2fait référence à cela /a/very/long/path/name. Il pourrait aussi être mycd 1, mycd 3... etc.

Le problème est que je dois écrire en mycdtant que script shell et taper . mycd 2pour faire la chose désirée car sinon le script est simplement exécuté dans un script enfant qui ne change rien au shell parent dont je me soucie réellement.

Ma question est:

  • puis-je le faire sans utiliser source? car . mycdsuppose qu'il mycddoit s'agir d'un script shell et cela pourrait également introduire certaines fonctions dont je ne veux pas.

  • puis-je l'implémenter dans d'autres langages de programmation?

Javran
la source

Réponses:

23

créer mycdune fonction pour que la cdcommande s'exécute dans votre shell actuel. Enregistrez-le dans votre fichier ~ / .bashrc.

function mycd {
    if (( $# == 0 )); then
        echo "usage: $FUNCNAME [1|2|3|...]"
        return
    fi
    case $1 in
        1) cd /tmp ;;
        2) cd /a/very/long/path/name ;;
        3) cd /some/where/else ;;
        *) echo "unknown parameter" ;;
    esac
}
glenn jackman
la source
Merci, vous n'avez pas pensé à utiliser les fonctions, et cela permet tout: je peux maintenant laisser mycdpasser $@n'importe quel programme que j'aime.
Javran
Assurez-vous de citer "$@"afin que tous les arguments contenant des espaces soient traités correctement.
glenn jackman
9

Vous ne pouvez pas changer le répertoire courant d'un shell à partir d'un autre processus. Seul le processus lui-même peut changer son propre répertoire courant. Cela vaut également pour d'autres caractéristiques telles que les variables d'environnement et les descripteurs de fichiers.

Il est en fait possible d'affecter le répertoire actuel d'un autre processus en le faisant exécuter un chdirappel système via l' ptraceappel système, ce qui permet aux débogueurs de fonctionner. Cependant, si le processus conserve certaines structures de données internes qui doivent être cohérentes avec le répertoire actuel, le programme risque de se bloquer. Pour un shell, cette approche n'a aucune chance de fonctionner.

Vous devez organiser l'exécution de votre code par le shell lui-même. La manière normale de procéder serait d'en faire une fonction shell et de la stocker dans votre ~/.bashrc. Si ce n'est pas possible, par exemple parce que c'est du code que vous souhaitez distribuer, écrivez un fichier source de shell qui contient la définition de la fonction et dites aux gens de faire lire leur fichier par leur shell interactif avec la .commande .

Gilles 'SO- arrête d'être méchant'
la source
1
Il y a en fait une chance de le faire "fonctionner", mais il est non trivial, sujet aux erreurs et devrait être évité à tout prix. Pour montrer qu'il est réellement « possible », considérez ce script shell où le parent est Bash: ws=$1; gdb -p $(ps h -o ppid -p $$) -ex "call chdir(\"$wd\")" -ex "call set_working_directory(\"$wd\")" -ex detach -ex q -batch. Exécuter en tant que braindead-cd-parent /. Vous verrez que les pwdretours /et ainsi ls, etc. se comportent. Mais l'invite ( PS1) est toujours inchangée, les yeux des gens sont blessés, etc. Ne faites donc pas cela même si c'est possible.
Lekensteyn
1
@Lekensteyn C'est la ptraceméthode que je mentionne. Cela fonctionne bien sur les programmes qui ne se soucient pas beaucoup de leur répertoire actuel. Dans un shell, beaucoup de choses ( PWDvariables, invite, etc.) vont se tromper, et le shell peut se bloquer ou mal se comporter autrement.
Gilles 'SO- arrête d'être méchant'
5

Comme vous l'avez souligné vous-même, les scripts shell sont toujours exécutés dans un sous-shell, ce qui ne peut pas influencer son shell parent.

Vous pouvez cependant ...

  • utilisez un alias:
    alias mycd2='cd /a/very/long/path/name'
  • que votre script 1 génère une commande shell valide ...

    #!/bin/bash
    if [ "x$1" = "x2" ]
    then
        echo "cd /a/very/long/path/name"
    fi

    ... et exécutez sa sortie: $(mycd 2)

1: Vous souhaiterez probablement utiliser une caseinstruction plutôt que la ifcondition dans l'exemple.

n.st
la source
5
Un alias est passable. Un script est le même problème qu'il a déjà. Cette question crie la fonction shell.
Ricky Beam