Warum funktioniert "cd" in einem Shell-Skript nicht?

43

Ich möchte nur ein Skript schreiben, das mein Verzeichnis ändert .

Ich habe die folgenden Befehle in die Datei eingefügt /home/alex/pathABC

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

Ich habe es getan chmod +x pathABC.

Im Terminal, während /home/alexich in bin, laufe ich ./pathABC, aber die Ausgabe ist gerecht HelloWorldund das aktuelle Verzeichnis wird nicht geändert.

Also, was ist los?

Mohammad Reza Rezwani
quelle

Antworten:

74

Wie andere bereits erklärt haben, wird das Verzeichnis im untergeordneten Prozess Ihres Skripts geändert, nicht im Terminalprozess, von dem aus das Skript aufgerufen wird. Nachdem der untergeordnete Prozess gestorben ist, befinden Sie sich wieder in dem Terminal, in dem es sich befunden hat.

Mehrere Alternativen:

1. Symbolischer Link

Platzieren Sie einen Symlink in Ihrem Zuhause auf dem langen Weg, auf den Sie problemlos zugreifen möchten

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

Greifen Sie dann auf das Verzeichnis zu mit:

$ cd ~/pathABC

2. Alias

Fügen Sie einen Alias ​​in Ihre ~ / .bashrc ein:

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

(von hier )

3. Funktion

Erstellen Sie eine Funktion, die das Verzeichnis ändert. Die Funktion wird auf Ihrem Terminal ausgeführt und kann dann das Verzeichnis ändern.

(von hier )

4. Vermeiden Sie es, als Kind zu rennen

Quell dein Skript, anstatt es auszuführen. Sourcing (durchgeführt von .oder source) bewirkt, dass das Skript in derselben Shell ausgeführt wird, anstatt in einer eigenen Subshell.

$ . ./pathABC

(von hier und hier )

5. cd-fähige vars

Setzen Sie die cdable_varsOption in Ihrem ~/.bashrcund erstellen Sie eine Umgebungsvariable für das Verzeichnis:

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

Dann können Sie verwenden cd pathABC

(von hier )

Gauthier
quelle
15
Jetzt verstehe ich die Verwendung von source! Ich habe mich immer gefragt, warum ich das tue source .bashrcund nichtbash .bashrc
hytromo
Option 3 hat super funktioniert. Ich habe gerade eine Funktion go_to_wherever () {cd my / directory} am Anfang meines Skripts definiert. Wurde aufgerufen, bevor die Vorgänge in diesem Verzeichnis ausgeführt wurden.
i2097i
> 5. cd-fähige vars - nicht wahr cd $pathABC?
loxaxs
7

Wenn Sie ein Skript in einem Terminal ausführen, wird ein untergeordneter Prozess ausgeführt. In diesem untergeordneten Programm wechselt Ihr Skript in das angegebene Verzeichnis. Aber im übergeordneten Prozess, dh wo Sie das Skript ausführen, befindet sich noch der alte Pfad. ODER wir können einfach sagen:

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

Tingrammer
quelle
2
Fügen Sie @alex hinzu, um den gewünschten Effekt zu erzielen, und führen Sie das Skript im übergeordneten Prozess aus, indem Sie entweder . pathABCoder angeben source pathABC.
zwets
4

Sie machen einen Denkfehler. Während sich die aktuelle Shell im selben Verzeichnis befindet, wurde das Skript in das neue Verzeichnis verschoben.

Sie können dies feststellen, indem Sie ein anderes Skript im neuen Verzeichnis erstellen und von Ihrem Skript ausführen, nachdem es das Verzeichnis geändert hat:

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

Das zweite Skript würde aus dem neuen Verzeichnis ausgeführt.

HelloWorld 

ist nur die Ausgabe des Skripts.

Jacob Vlijm
quelle
3
HelloWorld wird nicht an die übergeordnete Shell "zurückgegeben", sondern an die Standardausgabe
Mog
Könnte klarer sein, wenn Sie nur pwdim neuen Verzeichnis ausgeführt werden, anstatt der Situation ein ganz neues Skript hinzuzufügen.
Wjandrea
0

Da hallo Welt nur eine Trace-Anweisung ist, versuchen wir Folgendes:

Erstellen Sie eine Bash-Skript-Datei cd.shmit:

#!/bin/bash
echo "/home/mike/Documents/A/B/C"
  • Die .shErweiterung ist eine ältere Konvention, nach der Dateinamen von Bash-Skripten erweitert werden. Es ist rein kosmetisch und normalerweise unnötig. In diesem Fall ist es jedoch wichtig, sich vom Kernbefehl zu unterscheiden cd.

Markieren Sie die ausführbare Bash-Skriptdatei mit:

chmod a+x cd.sh

Führen Sie nun die Datei aus:

$ cd $(./cd.sh)
bash: cd: /home/alex/Documents/A/B/C: No such file or directory
  • cd wir wissen alle.
  • $(...) Führt den Befehl in Klammern aus und gibt die Ausgabe zurück.
  • Wenn cd.shin Ihrem Pfad war, müssen Sie nicht angeben, wo es ist. Wir setzen das Präfix, ./um anzugeben, dass sich der Befehl im aktuellen Verzeichnis befindet.
  • Die echoAusgabe des cd.shSkripts wird über die an das übergeordnete Element zurückgesendet $(...). Das übergeordnete Element (unsere Shell-Eingabeaufforderung) verwendet diese Ausgabe und übergibt sie an den Linux- cdBefehl.

Wie andere bereits erwähnt haben, kann ein untergeordneter Prozess das übergeordnete Verzeichnis nicht ändern. Auf diese Weise kann das Kind dem Elternteil mitteilen, wohin es nach Beendigung des Prozesses gehen soll.

WinEunuuchs2Unix
quelle
@wjandrea Das ist, was Sie für die Codierung auf einem Telefon bekommen! Komme gerade nach Hause, ich werde es reparieren. Vielen Dank. Um gerade überprüft und es funktioniert gut. Vielleicht ist es deine 14.04Version, die ich vor ungefähr einer Stunde gelesen habe?
WinEunuuchs2Unix
Nun, Sie haben das Skript komplett geändert. Bisher war es nur ein Befehl cd /home/mike/Documents/A/B/C:, der keine Ausgabe erzeugte. Jetzt ist es echo "/home/mike/Documents/A/B/C", was Output erzeugt.
wjandrea
@wjandrea Stimmt, ich habe auch die Art und Weise, wie das Skript aufgerufen wird, grundlegend geändert. Statt eines einfachen ist ./cd.shes jetzt, cd $(./cd.sh)aber es erreicht das Ziel, dass das Kind das aktuelle Verzeichnis des Elternteils ändert. Ja, es ist unkonventionell, aber ich hoffe, die Leute finden es auch interessant.
WinEunuuchs2Unix