Perché "cd" non funziona in uno script di shell?


43

Voglio solo scrivere uno script che cambi la mia directory .

Ho inserito i seguenti comandi nel file /home/alex/pathABC

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

L'ho fatto chmod +x pathABC.

Nel terminale, mentre in /home/alex, corro ./pathABC, ma l'output è giusto HelloWorlde la directory corrente non è cambiata.

Quindi cosa c'è che non va?


Risposte:


74

Come altri hanno spiegato, la directory viene modificata nel processo figlio dello script, non nel processo terminale da cui viene chiamato lo script. Dopo la morte del processo figlio, si ritorna nel terminale che è rimasto dov'era.

Diverse alternative:

1. Collegamento simbolico

Inserisci un link simbolico nella tua casa per il lungo percorso a cui desideri accedere facilmente

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

quindi accedi alla directory con:

$ cd ~/pathABC

2. Alias

Inserisci un alias nel tuo ~ / .bashrc:

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

(da qui )

3. Funzione

Crea una funzione che modifica la directory, la funzione viene eseguita nel processo del tuo terminale e può quindi cambiare la sua directory.

(da qui )

4. Evitare di correre da bambino

Sorgi il tuo script invece di eseguirlo. Il sourcing (eseguito da .o source) fa sì che lo script venga eseguito nella stessa shell invece di essere eseguito nella propria subshell.

$ . ./pathABC

(da qui e qui )

5. Vars cd-grado

Imposta l' cdable_varsopzione nella tua ~/.bashrce crea una variabile d'ambiente nella directory:

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

Quindi puoi usare cd pathABC

(da qui )


15
Ora capisco l'uso di source! Mi sono sempre chiesto perché lo faccio source .bashrce nobash .bashrc
hytromo l'

L'opzione 3 ha funzionato alla grande. Ho appena definito una funzione go_to_wherever () {cd my / directory} all'inizio del mio script. Chiamato prima di eseguire le operazioni in quella directory.
i2097i,

> 5. Vars con capacità cd - non è vero cd $pathABC?
Loxaxs

7

Quando si esegue uno script in un terminale, viene eseguito un processo figlio. In questo programma figlio, ovvero lo script cambierà in qualunque directory specificata. Ma nel processo genitore, ovvero dove si esegue lo script, è ancora nel vecchio percorso. O semplicemente possiamo dire:

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


2
Aggiungendo a questo, @alex per ottenere l'effetto che stai cercando, esegui lo script all'interno del processo genitore acquistandolo: o . pathABCoppure source pathABC.
zwets,

4

Stai commettendo un errore di pensiero. Mentre la shell corrente rimane nella stessa directory, lo script è stato spostato nella nuova directory.

Potresti vederlo creando un altro script nella nuova directory ed eseguendolo dal tuo script, dopo che ha cambiato directory:

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

Il secondo script verrebbe eseguito dalla nuova directory.

HelloWorld 

è solo l'output dello script.


3
HelloWorld non viene "restituito" alla shell genitore, viene emesso nell'output standard
Mog

Potrebbe essere più chiaro se si esegue semplicemente pwdnella nuova directory, invece di aggiungere uno script completamente nuovo alla situazione.
wjandrea,

0

Perché ciao mondo è solo una dichiarazione di traccia, proviamo questo:

Crea un file di script bash cd.shcontenente:

#!/bin/bash
echo "/home/mike/Documents/A/B/C"
  • L' .shestensione è una vecchia convenzione di dare un'estensione ai nomi dei file di script bash. È puramente cosmetico e di solito non necessario. Tuttavia, in questo caso è importante distinguere dal cdcomando principale .

Contrassegna l'eseguibile del file di script bash usando:

chmod a+x cd.sh

Ora esegui il file:

$ cd $(./cd.sh)
bash: cd: /home/alex/Documents/A/B/C: No such file or directory
  • cd lo sappiamo tutti.
  • $(...) esegue il comando tra parentesi e restituisce l'output.
  • Se cd.shera sul tuo percorso non è necessario specificare dove si trova. Abbiamo il prefisso ./per specificare che il comando si trova nella directory corrente.
  • L' echooutput dello cd.shscript viene rinviato al genitore tramite il $(...). Il genitore (il nostro prompt della shell) utilizza questo output e lo passa al cdcomando Linux .

Come altri hanno già detto, un processo figlio non può cambiare la directory del genitore. Questo è un modo in cui il bambino può dire al genitore dove andare dopo la fine del processo.


@wjandrea Ecco cosa ottieni per la programmazione su un telefono! Sono appena tornato a casa, lo aggiusterò. Grazie. Ho appena controllato e funziona benissimo. Forse è la tua 14.04versione che ho letto circa un'ora fa?
WinEunuuchs2Unix

Bene, hai completamente cambiato la sceneggiatura. In precedenza era solo un comando:, cd /home/mike/Documents/A/B/Cche non produceva alcun output. Ora è echo "/home/mike/Documents/A/B/C", che produce output.
wjandrea,

@wjandrea Vero, ho anche completamente cambiato il modo di chiamare la sceneggiatura. Invece di un semplice ./cd.shè ora cd $(./cd.sh)ma raggiunge l'obiettivo del bambino di cambiare la directory corrente del genitore. Sì, non è convenzionale ma è un altro modo di farlo che spero che la gente trovi interessante.
WinEunuuchs2Unix
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.