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?


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 )


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


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.


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.


@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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.