Ist es möglich, das Arbeitsverzeichnis der übergeordneten Shell programmgesteuert zu ändern?

8

Ich möchte Code schreiben, damit ich zu einigen Verzeichnissen wechseln kann, in die ich normalerweise gehe. Angenommen, dieses Programm ist mycdund /a/very/long/path/nameist das Verzeichnis, in das ich gehen möchte.

So kann ich geben Sie einfach mycd 2statt cd /a/very/long/path/name. Hier gehe ich davon mycdweiß , 2bezieht sich auf das /a/very/long/path/name. Es könnte auch sein mycd 1, mycd 3... usw.

Das Problem ist, dass ich mycdals Shell-Skript schreiben und eingeben muss . mycd 2, um das gewünschte Ziel zu erreichen, da das Skript sonst nur in einem untergeordneten Skript ausgeführt wird, das nichts an der übergeordneten Shell ändert, die mir wirklich wichtig ist.

Meine Frage ist:

  • kann ich es ohne verwenden source? weil . mycddavon ausgegangen mycdwird, dass es sich um ein Shell-Skript handeln muss und dies möglicherweise auch einige Funktionen einführt, die ich nicht möchte.

  • Kann ich es in einigen anderen Programmiersprachen implementieren?

Javran
quelle

Antworten:

23

Erstellen Sie mycdeine Funktion, damit der cdBefehl in Ihrer aktuellen Shell ausgeführt wird. Speichern Sie es in Ihrer ~ / .bashrc-Datei.

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
quelle
Vielen Dank, hat über die Verwendung von Funktionen nicht gedacht, und das alles nur ermöglicht: ich jetzt lassen kann mycdpassieren $@zu jedem Programm , die ich mag.
Javran
Stellen Sie sicher, dass Sie zitieren, "$@"damit alle Argumente, die Leerzeichen enthalten, korrekt behandelt werden.
Glenn Jackman
9

Sie können das aktuelle Verzeichnis einer Shell nicht von einem anderen Prozess ändern. Nur der Prozess selbst kann sein eigenes aktuelles Verzeichnis ändern. Dies gilt auch für einige andere Merkmale wie Umgebungsvariablen und Dateideskriptoren.

Es ist tatsächlich möglich, das aktuelle Verzeichnis eines anderen Prozesses zu beeinflussen, indem ein chdirSystemaufruf über den ptraceSystemaufruf ausgeführt wird, wodurch Debugger arbeiten können. Wenn der Prozess jedoch einige interne Datenstrukturen verwaltet, die mit dem aktuellen Verzeichnis übereinstimmen müssen, stürzt das Programm wahrscheinlich ab. Für eine Shell hat dieser Ansatz keine Chance zu funktionieren.

Sie müssen dafür sorgen, dass Ihr Code von der Shell selbst ausgeführt wird. Die normale Vorgehensweise wäre, es zu einer Shell-Funktion zu machen und in Ihrer zu speichern ~/.bashrc. Wenn dies nicht möglich ist, z. B. weil Sie Code verteilen möchten, schreiben Sie eine Shell-Quelldatei, die die Funktionsdefinition enthält, und weisen Sie die Benutzer an, ihre Datei mit dem .Befehl von ihrer interaktiven Shell lesen zu lassen .

Gilles 'SO - hör auf böse zu sein'
quelle
1
Es gibt tatsächlich eine Chance, dass es "funktioniert", aber es ist nicht trivial, fehleranfällig und sollte unter allen Umständen vermieden werden. Um zu zeigen, dass es tatsächlich "möglich" ist, betrachten Sie dieses Shell-Skript, bei dem das übergeordnete Element Bash ist : ws=$1; gdb -p $(ps h -o ppid -p $$) -ex "call chdir(\"$wd\")" -ex "call set_working_directory(\"$wd\")" -ex detach -ex q -batch. Ausführen als braindead-cd-parent /. Sie werden sehen, dass sich pwdRückkehr /und lsVerhalten usw. verhalten. Aber die Eingabeaufforderung ( PS1) bleibt unverändert, die Augen der Menschen sind verletzt usw. Tun Sie dies also nicht, auch wenn dies möglich ist.
Lekensteyn
1
@Lekensteyn Das ist die ptraceMethode, die ich erwähne. Es funktioniert gut bei Programmen, denen das aktuelle Verzeichnis egal ist. In einer Shell werden viele Dinge ( PWDVariable, Eingabeaufforderung usw.) falsch sein, und die Shell kann abstürzen oder sich auf andere Weise schlecht verhalten.
Gilles 'SO - hör auf böse zu sein'
5

Wie Sie selbst betont haben, werden Shell-Skripte immer in einer Subshell ausgeführt, die die übergeordnete Shell nicht beeinflussen kann.

Sie können jedoch ...

  • Verwenden Sie einen Alias:
    alias mycd2='cd /a/very/long/path/name'
  • Lassen Sie Ihr Skript 1 einen gültigen Shell-Befehl ausgeben ...

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

    ... und seine Ausgabe ausführen: $(mycd 2)

1: Sie möchten wahrscheinlich caseeher eine Anweisung als die ifBedingung im Beispiel verwenden.

n.st
quelle
5
Ein Alias ​​ist passabel. Ein Skript ist das gleiche Problem, das er bereits hat. Diese Frage schreit nach Shell-Funktion.
Ricky Beam