web-dev-qa-db-de.com

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

Ich versuche, ein kleines Skript zu schreiben, um das aktuelle Verzeichnis in mein Projektverzeichnis zu ändern:

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

Ich habe diese Datei als Projekt gespeichert, die Ausführungsberechtigung mit chmod hinzugefügt und sie nach /usr/bin kopiert. Wenn ich es mit: proj anrufe, macht es nichts. Was mache ich falsch?

656
ashokgelal

Shell-Skripts werden in einer Subshell ausgeführt, und jede Subshell verfügt über ein eigenes Konzept des aktuellen Verzeichnisses. Die Variable cd ist erfolgreich, aber sobald die Subshell beendet ist, sind Sie wieder in der interaktiven Shell und es hat sich nichts geändert.

Um dies zu umgehen, verwenden Sie stattdessen einen Alias:

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

Du machst nichts falsch! Sie haben das Verzeichnis geändert, jedoch nur innerhalb der Subshell, in der das Skript ausgeführt wird.

Sie können das Skript in Ihrem aktuellen Prozess mit dem Befehl "dot" ausführen:

. proj

Aber ich würde Gregs Vorschlag vorziehen, in diesem einfachen Fall einen Pseudonym zu verwenden.

438
Adam Liss

Die cd in Ihrem Skript hat technisch funktioniert, als es das Verzeichnis der Shell, in der das Skript ausgeführt wurde, geändert hat. Dies war jedoch ein separater Prozess, der von Ihrer interaktiven Shell getrennt wurde.

Eine Posix-kompatible Möglichkeit, dieses Problem zu lösen, besteht darin, eine Shell-Prozedur und nicht ein von der Shell aufgerufenes Befehlsskript zu definieren.

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

Sie können dies einfach eingeben oder in eine der verschiedenen Shell-Startdateien einfügen.

205
DigitalRoss

Die Variable cd erfolgt in der Shell des Skripts. Wenn das Skript beendet ist, wird diese Shell beendet und Sie verbleiben in dem Verzeichnis, in dem Sie sich befanden. "Source" das Skript ausführen, nicht ausführen. Anstatt:

./myscript.sh

tun

. ./myscript.sh

(Beachten Sie den Punkt und das Leerzeichen vor dem Skriptnamen.)

135
Tzachi.e

So erstellen Sie ein Bash-Skript, das ein Auswahlverzeichnis erstellt:

Erstellen Sie die Skriptdatei

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

Dann erstellen Sie einen Alias ​​in Ihrer Startdatei.

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

  • Ich habe eine Startdatei erstellt, in der alle Aliase und benutzerdefinierten Funktionen gespeichert werden.
  • Dann gebe ich diese Datei in meine .bashrc-Datei ein, damit sie bei jedem Start festgelegt wird.

Erstellen Sie beispielsweise eine Master-Aliase/Funktionsdatei: /scripts/mastercode.sh
(Fügen Sie den Alias ​​in diese Datei ein.)

Dann am Ende deines .bashrc Datei:

 source /scripts/mastercode.sh



Jetzt ist es einfach, in Ihr Java-Verzeichnis zu cd. Geben Sie einfach cdjava ein und Sie sind da.

90
Matt Thomas

Jeremy Rutens Idee, einen Symlink zu verwenden, löste einen Gedanken aus, der keiner anderen Antwort entgegentrat. Benutzen:

CDPATH=:$HOME/projects

Der führende Doppelpunkt ist wichtig; Das heißt, wenn sich im aktuellen Verzeichnis ein Verzeichnis 'dir' befindet, ändert sich 'cd dir' in dieses Verzeichnis, anstatt an einem anderen Ort abzusteigen. Wenn der Wert wie gezeigt eingestellt ist, können Sie Folgendes tun:

cd Java

wenn sich im aktuellen Verzeichnis kein Unterverzeichnis mit der Bezeichnung Java befindet, gelangen Sie direkt zu $ ​​HOME/projects/Java - keine Aliase, keine Skripts, keine zweifelhaften Execs oder Punktbefehle.

Mein $ HOME ist/Users/jleffler; mein $ CDPATH ist:

:/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

Sie können . verwenden, um ein Skript in der aktuellen Shell-Umgebung auszuführen:

. script_name

oder alternativ dessen lesbarer, aber Shell-spezifischer Alias ​​source:

source script_name

Dadurch wird die Subshell vermieden und es können stattdessen Variablen oder Buildins (einschließlich cd) die aktuelle Shell beeinflussen.

33
Astha

Ich habe meinen Code mit . <your file name> zum Laufen gebracht.

./<your file name> funktioniert nicht, da das Verzeichnis im Terminal dadurch nicht geändert wird. Es ändert lediglich das für dieses Skript spezifische Verzeichnis. 

Hier ist mein Programm

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

Hier ist mein Terminal 

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

Verwenden Sie am Ende exec bash

Ein Bash-Skript arbeitet in seiner aktuellen Umgebung oder in der seiner Kinder, aber niemals in der übergeordneten Umgebung.

Diese Frage wird jedoch häufig gestellt, weil man nach der Ausführung eines Bash-Skripts aus einem anderen Verzeichnis an einem Bash-Prompt in einem bestimmten Verzeichnis verbleiben möchte.

Wenn dies der Fall ist, führen Sie einfach eine untergeordnete Bash-Instanz am Ende des Skripts aus:

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

einfach laufen lassen:

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

Wenn Sie ein Shell-Skript auslösen, wird eine new -Instanz dieser Shell (/bin/bash) ausgeführt. Daher startet Ihr Skript nur eine Shell, ändert das Verzeichnis und wird beendet. Anders ausgedrückt: cd (und andere derartige Befehle) innerhalb eines Shell-Skripts haben keinen Einfluss auf die Shell, von der sie gestartet wurden, und haben keinen Zugriff darauf.

11
Daniel Spiewak

In meinem speziellen Fall musste ich zu oft für dasselbe Verzeichnis wechseln. Also habe ich auf meiner .bashrc (ich benutze Ubuntu) die 

1 -

$ nano ~./bashrc

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

2- 

$ source ~/.bashrc

3 - 

$ switchp Java

Direkt wird es tun: cd/home/tree/projects/Java

Hoffentlich hilft das!

9
workdreamer

Sie können folgendes tun:

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

BEARBEITEN: Dies kann auch "punktiert" sein, um die Erzeugung nachfolgender Schalen zu verhindern.

Beispiel:

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

Sie können einen Alias ​​und ein Skript kombinieren,

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

sofern das Skript den Zielpfad enthält. Beachten Sie, dass es sich um Backticks handelt, die den Skriptnamen umgeben.

Zum Beispiel könnte Ihr Skript sein

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

Der Vorteil dieser Technik besteht darin, dass das Skript eine beliebige Anzahl von Befehlszeilenparametern verwenden und verschiedene Ziele ausgeben kann, die von möglicherweise komplexer Logik berechnet werden.

7
J. A. Faucett

Es ändert nur das Verzeichnis für das Skript selbst, während Ihr aktuelles Verzeichnis gleich bleibt.

Möglicherweise möchten Sie stattdessen einen symbolischen Link verwenden. Sie können eine Verknüpfung zu einer Datei oder einem Verzeichnis erstellen, sodass Sie nur etwas wie cd my-project eingeben müssen.

7
Jeremy Ruten
5
Gene T

Sie können die Alias- und Punktansätze von Adam & Greg kombinieren, um etwas dynamischer zu gestalten -

alias project=". project"

Beim Ausführen des Projektalias wird das Projektskript jetzt in der aktuellen Shell und nicht in der Subshell ausgeführt. 

5
mogga

In Ihrer Datei ~/.bash_profile. fügen Sie die nächste Funktion hinzu

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

Starten Sie das Terminal neu und Sie können tippen

move_me 

und Sie werden in den Zielordner verschoben.

3
mihai.ciorobea

Während das Beschreiben des Skripts, das Sie ausführen möchten, eine Lösung ist, sollten Sie wissen, dass dieses Skript die Umgebung Ihrer aktuellen Shell direkt ändern kann. Es ist auch nicht mehr möglich, Argumente zu übergeben.

Eine andere Möglichkeit besteht darin, Ihr Skript als Funktion in bash zu implementieren.

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

Diese Methode wird von autojump verwendet: http://github.com/joelthelion/autojump/wiki , um Ihnen das Lernen von Shell-Verzeichnis-Lesezeichen zu ermöglichen.

3
thomasd

Dies sollte tun, was Sie wollen. Wechseln Sie in das Verzeichnis von Interesse (aus dem Skript heraus) und erstellen Sie eine neue Bash-Shell.

#!/bin/bash

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

Wenn Sie dies ausführen, werden Sie zu dem Verzeichnis von Interesse geleitet, und wenn Sie es beenden, werden Sie zum ursprünglichen Ort zurückgebracht.

[email protected]:~# ./mov_dir.sh

[email protected]:~/mt/v3/rt_linux-rt-tools# exit
[email protected]:~#

Dadurch gelangen Sie beim Beenden sogar wieder in Ihr ursprüngliches Verzeichnis (CTRL+d)

3
jithu83

Sie können den Operator && verwenden:

cd meinVerzeichnis && ls

3
Jack Bauer

LOOOOOng Zeit danach, aber ich habe folgendes getan:

erstellen Sie eine Datei namens case

fügen Sie Folgendes in die Datei ein:

#!/bin/sh

cd /home/"$1"

speichern Sie es und dann:

chmod +x case

Ich habe auch einen Alias ​​in meinem .bashrc angelegt:

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

jetzt wenn ich tippe:

case 12345

im Wesentlichen schreibe ich:

cd /home/12345

Sie können einen beliebigen Ordner nach 'case' eingeben:

case 12

case 15

case 17

was ist wie das Tippen:

cd /home/12

cd /home/15

cd /home/17

beziehungsweise

In meinem Fall ist der Weg viel länger - diese Jungs haben ihn früher mit der ~ Info zusammengefasst.

2
chris

Sie können eine Funktion wie unten in Ihrem .bash_profile erstellen und sie funktioniert reibungslos.

Die folgende Funktion benötigt einen optionalen Parameter, der ein Projekt ist. __ Sie können beispielsweise einfach ausführen

cdproj

oder

cdproj project_name

Hier ist die Funktionsdefinition.

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

Vergessen Sie nicht, Ihren .bash_profile zu beziehen

1
Krish

Sie benötigen kein Skript, setzen nur die richtige Option und erstellen eine Umgebungsvariable.

shopt -s cdable_vars

in Ihrem ~/.bashrc erlaubt cd den Inhalt von Umgebungsvariablen.

Erstellen Sie eine solche Umgebungsvariable:

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

und du kannst verwenden:

cd myjava

Andere Alternativen .

0
Gauthier

Wenn Sie fish als Shell verwenden, ist es am besten, eine Funktion zu erstellen. Als Beispiel könnten Sie bei Vorlage der ursprünglichen Frage die folgenden vier Zeilen kopieren und in Ihre Fischbefehlszeile einfügen:

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

Dadurch wird die Funktion erstellt und zur späteren Verwendung gespeichert. Wenn sich Ihr Projekt ändert, wiederholen Sie den Vorgang einfach mit dem neuen Pfad.

Wenn Sie möchten, können Sie die Funktionsdatei manuell hinzufügen, indem Sie folgende Schritte ausführen:

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

und geben Sie den Text ein:

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

und zum Schluss drücken Sie zum Verlassen Strg + x und y gefolgt von Return, um Ihre Änderungen zu speichern.

(HINWEIS: Die erste Methode zur Verwendung von funcsave erstellt die Datei "proj.fish" für Sie).

0
Lane Roathe

Ich habe ein einfaches Bash-Skript namens p, um das Verzeichnis zu ändern
github.com/godzilla/bash-stuff
Legen Sie das Skript in Ihr lokales bin-Verzeichnis (/ usr/local/bin)
und legen

alias p='. p'

in Ihrer .bashrc 

0
godzilla

Verwenden von Bash-Profilfunktionen:

Eine Funktion des bash-Profils besteht darin, benutzerdefinierte Funktionen zu speichern, die im Terminal oder in bash-Skripts ausgeführt werden können, genauso wie bei der Ausführung von Anwendung/Befehlen. 

Um Ihre Funktion effizient zu gestalten, müssen Sie Ihre Funktion am Ende mehrerer Dateien kopieren

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

Sie können Sudo kwrite /home/user/.bashrc /home/user/.bash_profile /root/.bashrc /root/.bash_profile diese Dateien schnell bearbeiten/erstellen

Skriptbeispiel

Verknüpfung zu cd .. mit cdd erstellen

cdd() {
  cd ..
}

ls Abkürzung

ll() {
  ls -l -h
}

ls Abkürzung

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

Wie man :

Kopieren Sie Ihre Funktion am Ende Ihrer Dateien und starten Sie Ihr Terminal neu. Anschließend können Sie cdd oder die von Ihnen geschriebene Funktion ausführen

0
intika

Beachten Sie die Diskussion Wie lege ich das Arbeitsverzeichnis des übergeordneten Prozesses fest?

Es enthält einige hackhafte Antworten, zB https://stackoverflow.com/a/2375174/755804 (Ändern des übergeordneten Prozessverzeichnisses über gdb, machen Sie das nicht) und https: // stackoverflow .com/a/51985735/755804 (der Befehl tailcd, der cd dirname in den Eingabestrom des übergeordneten Prozesses einfügt; im Idealfall sollte dies ein Teil von bash und nicht ein Hack sein)