Dlaczego „cd” nie działa w skrypcie powłoki?

43

Chcę tylko napisać skrypt, który zmieni mój katalog .

Umieszczam poniższe polecenia w pliku /home/alex/pathABC

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

Zrobiłem chmod +x pathABC.

W terminalu, podczas gdy /home/alexja, uruchamiam ./pathABC, ale dane wyjściowe są tylko HelloWorldi bieżący katalog nie jest zmieniany.

Więc co jest nie tak?

Mohammad Reza Rezwani
źródło

Odpowiedzi:

74

Jak wyjaśnili inni, katalog jest zmieniany w procesie potomnym skryptu, a nie w procesie terminalowym, z którego skrypt jest wywoływany. Po śmierci procesu potomnego wracasz do terminala, który został tam, gdzie był.

Kilka alternatyw:

1. Link symboliczny

Umieść w swoim domu symboliczne łącze do długiej ścieżki, do której chcesz łatwo uzyskać dostęp

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

następnie przejdź do katalogu za pomocą:

$ cd ~/pathABC

2. Alias

Umieść alias w swoim ~ / .bashrc:

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

( stąd )

3. Funkcja

Utwórz funkcję, która zmienia katalog, funkcja działa w trakcie działania twojego terminala, a następnie może zmienić jego katalog.

( stąd )

4. Unikaj biegania jako dziecko

Źródło skryptu zamiast go uruchamiać. Sourcing (wykonywany przez .lub source) powoduje, że skrypt jest wykonywany w tej samej powłoce, a nie we własnej podpowłoce.

$ . ./pathABC

( stąd i tutaj )

5. Vars z obsługą CD

Ustaw cdable_varsopcję w swoim ~/.bashrci utwórz zmienną środowiskową do katalogu:

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

Następnie możesz użyć cd pathABC

( stąd )

Gauthier
źródło
15
Teraz rozumiem użycie source! Zawsze zastanawiałem się, dlaczego tak robię, source .bashrca niebash .bashrc
hytromo,
Opcja 3 działała świetnie. Właśnie zdefiniowałem funkcję go_to_wherever () {cd my / directory} na początku mojego skryptu. Wywołano go przed uruchomieniem operacji w tym katalogu.
i2097i
> 5. Vars z obsługą CD - prawda cd $pathABC?
loxaxs
7

Po uruchomieniu skryptu w terminalu uruchamiany jest proces potomny. W tym programie potomnym, tj. Skrypt zmieni się na dowolny określony katalog. Ale w procesie nadrzędnym, tzn. Gdzie uruchamiasz skrypt, wciąż znajduje się on na starej ścieżce. LUB po prostu możemy powiedzieć:

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

Tingrammer
źródło
2
Dodając do tego, @alex aby osiągnąć efekt, którego szukasz, wykonanie skryptu w ciągu procesu nadrzędnego poprzez pozyskiwanie go: albo . pathABCalbo source pathABC.
zwets
4

Popełniasz błąd myślenia. Podczas gdy bieżąca powłoka pozostaje w tym samym katalogu, skrypt został przeniesiony do nowego katalogu.

Można to zobaczyć, tworząc inny skrypt w nowym katalogu i uruchamiając go ze skryptu po zmianie katalogu:

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

Drugi skrypt uruchomi się z nowego katalogu.

HelloWorld 

jest tylko wynikiem działania skryptu.

Jacob Vlijm
źródło
3
HelloWorld nie jest „zwracany” do powłoki nadrzędnej, jest wyprowadzany na standardowe wyjście
Mog
Może być bardziej zrozumiałe, jeśli po prostu uruchomisz pwdnowy katalog, zamiast dodawać całkiem nowy skrypt do sytuacji.
wjandrea
0

Ponieważ hello world jest tylko instrukcją śledzenia, spróbujmy tego:

Utwórz plik skryptu bash cd.shzawierający:

#!/bin/bash
echo "/home/mike/Documents/A/B/C"
  • .shRozszerzenie jest starszy konwencja daje skrypt bash nazewnictwo rozszerzenie. Jest to czysto kosmetyczne i zwykle niepotrzebne. Jednak w tym przypadku ważne jest, aby odróżnić się od podstawowego cdpolecenia.

Zaznacz plik wykonywalny skryptu bash, używając:

chmod a+x cd.sh

Teraz uruchom plik:

$ cd $(./cd.sh)
bash: cd: /home/alex/Documents/A/B/C: No such file or directory
  • cd wszyscy wiemy.
  • $(...) wykonuje polecenie w nawiasie i zwraca dane wyjściowe.
  • Jeśli cd.shbył na twojej ścieżce, nie musisz określać, gdzie to jest. Używamy przedrostka, ./aby określić, że polecenie znajduje się w bieżącym katalogu.
  • Dane echowyjściowe cd.shskryptu są przesyłane z powrotem do rodzica za pośrednictwem $(...). Nadrzędny (nasz monit powłoki) korzysta z tych danych wyjściowych i przekazuje je do cdkomendy Linux .

Jak wspomnieli inni, proces potomny nie może zmienić katalogu rodzica. Jest to jeden ze sposobów, w jaki dziecko może powiedzieć rodzicowi, gdzie ma się udać po zakończeniu procesu.

WinEunuuchs2Unix
źródło
@wjandrea Właśnie to dostajesz za kodowanie na telefonie! Właśnie wróciłem do domu, naprawię to. Dzięki. Um właśnie sprawdziłem i działa dobrze. Może to twoją 14.04wersję przeczytałem około godzinę temu?
WinEunuuchs2Unix
Cóż, całkowicie zmieniłeś scenariusz. Wcześniej było to tylko jedno polecenie:, cd /home/mike/Documents/A/B/Cktóre nie dawało żadnych wyników. Teraz jest echo "/home/mike/Documents/A/B/C", co daje wynik.
wjandrea
@wjandrea To prawda, że ​​całkowicie zmieniłem również sposób wywoływania skryptu. Zamiast prostego ./cd.shjest teraz, cd $(./cd.sh)ale osiąga cel, jakim jest zmiana przez dziecko bieżącego katalogu nadrzędnego. Tak, to niekonwencjonalne, ale mam nadzieję, że ludzie uznają to za inny sposób.
WinEunuuchs2Unix