Perché “cd” non funziona in uno script di shell?

Sto provando a scrivere un piccolo script per cambiare la directory corrente nella directory del mio progetto:

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

Ho salvato questo file come proj, ho aggiunto il permesso di esecuzione con chmod e l’ho copiato in /usr/bin . Quando lo chiamo: proj , non fa nulla. Che cosa sto facendo di sbagliato?

Gli script di shell vengono eseguiti all’interno di una sottoshell e ciascuna subshell ha il proprio concetto di cosa sia la directory corrente. Il cd successo, ma non appena esce la subshell, sei di nuovo nella shell intertriggers e nulla è mai cambiato lì.

Un modo per aggirare questo è usare un alias invece:

 alias proj="cd /home/tree/projects/java" 

Stai facendo niente di sbagliato! Hai cambiato la directory, ma solo all’interno della sottoshell che esegue lo script.

Puoi eseguire lo script nel tuo processo corrente con il comando “punto”:

 . proj 

Ma preferirei il suggerimento di Greg di usare un alias in questo semplice caso.

Il cd nel tuo script ha funzionato tecnicamente come ha cambiato la directory della shell che ha eseguito lo script, ma quello era un processo separato biforcato dalla tua shell intertriggers.

Un modo compatibile con Posix per risolvere questo problema è definire una procedura di shell piuttosto che uno script di comando invocato dalla shell.

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

Puoi semplicemente inserirla o inserirla in uno dei vari file di avvio della shell.

Il cd è fatto all’interno della shell dello script. Al termine dello script, la shell viene chiusa e quindi si rimane nella directory in cui si trovava. “Fonte” lo script, non eseguirlo. Invece di:

 ./myscript.sh 

fare

 . ./myscript.sh 

(Nota il punto e lo spazio prima del nome dello script.)

Per creare uno script bash che esegua il cd in una directory selezionata:

Crea il file di script

 #! / Bin / sh
 # file: / scripts / cdjava
 #
 cd / home / askgelal / projects / java

Quindi crea un alias nel file di avvio.

 #! / Bin / sh
 # file / script / mastercode.sh
 #
 alias cdjava = '.  / Scripts / cdjava'

  • Ho creato un file di avvio in cui scarico tutti i miei alias e funzioni personalizzate.
  • Quindi io porto questo file nel mio .bashrc per farlo impostare su ogni avvio.

Ad esempio, creare un file alias / funzioni master: /scripts/mastercode.sh
(Inserisci l’alias in questo file.)

Quindi alla fine del tuo file .bashrc :

 fonte /scripts/mastercode.sh


Ora è facile da CD alla tua directory java, basta digitare cdjava e tu sei lì.

L’idea di Jeremy Ruten di usare un link simbolico ha innescato un pensiero che non ha attraversato altre risposte. Uso:

 CDPATH=:$HOME/projects 

Il colon leader è importante; significa che se c’è una directory ‘dir’ nella directory corrente, allora ‘ cd dir ‘ cambierà in quello, invece di saltar fuori da qualche altra parte. Con il valore impostato come mostrato, puoi fare:

 cd java 

e, se non c’è una sottodirectory chiamata java nella directory corrente, allora ti porterà direttamente a $ HOME / projects / java – nessun alias, nessun script, nessun exec dubbi o comandi punto.

Il mio $ HOME è / Users / jleffler; il mio $ CDPATH è:

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

Puoi usare per eseguire uno script nell’ambiente shell corrente:

 . script_name 

o in alternativa, la sua source alias più leggibile ma shell shell:

 source script_name 

Questo evita la subshell e permette a qualsiasi variabile o builtin (incluso cd ) di influenzare la shell corrente.

Ho usato il mio codice per lavorare . .

./ dose non funziona perché non cambia la tua directory nel terminale cambia solo la directory specifica per quello script.

Ecco il mio programma

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

Ecco il mio terminale

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

Usa exec bash alla fine

Uno script bash opera sul suo ambiente corrente o su quello dei suoi figli, ma mai sul suo ambiente padre.

Tuttavia, questa domanda viene spesso richiesta perché si vuole essere lasciati a un prompt bash in una determinata directory dopo l’esecuzione di uno script bash da un’altra directory.

Se questo è il caso, esegui semplicemente un’istanza di bash figlio alla fine dello script:

 #!/bin/bash cd /home/tree/projects/java exec bash 

semplicemente corri:

 cd /home/xxx/yyy && command_you_want 

Quando si triggers uno script di shell, viene eseguita una nuova istanza di tale shell ( /bin/bash ). Pertanto, lo script triggers una shell, modifica la directory ed esce. In altre parole, cd (e altri comandi di questo tipo) all’interno di uno script di shell non influenzano né hanno accesso alla shell da cui sono stati lanciati.

Nel mio caso particolare avevo bisogno di troppe volte per cambiare per la stessa directory. Quindi sul mio .bashrc (io uso Ubuntu) ho aggiunto il

1 –

$ nano ~. / bashrc

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

2-

$ fonte ~ / .bashrc

3 –

$ switchp java

Direttamente farà: cd / home / tree / projects / java

Spero possa aiutare!

Cambia solo la directory per lo script stesso, mentre la directory corrente rimane la stessa.

Potresti invece voler usare un link simbolico . Ti permette di creare una “scorciatoia” in un file o in una directory, quindi devi solo digitare qualcosa come cd my-project .

Puoi fare quanto segue:

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

EDIT: Potrebbe anche essere ‘punteggiato’, per impedire la creazione di shell successive.

Esempio:

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

Puoi combinare un alias e una sceneggiatura,

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

a condizione che lo script echi il percorso di destinazione. Si noti che questi sono backtick che circondano il nome dello script.

Ad esempio, il tuo script potrebbe essere

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

Il vantaggio di questa tecnica è che lo script può prendere qualsiasi numero di parametri da riga di comando ed emettere destinazioni diverse calcolate da una logica eventualmente complessa.

Puoi combinare gli alias e gli approcci punto di Adam & Greg per creare qualcosa che può essere più dinamico-

 alias project=". project" 

Ora l’alias del progetto eseguirà lo script del progetto nella shell corrente anziché nella subshell.

Puoi usare l’operatore &&:

cd myDirectory && ls

Nel tuo file ~ / .bash_profile. aggiungi la prossima funzione

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

Riavvia il terminale e puoi digitare

 move_me 

e verrai spostato nella cartella di destinazione.

Mentre l’individuazione dello script che si desidera eseguire è una soluzione, è necessario tenere presente che questo script può quindi modificare direttamente l’ambiente della shell corrente. Inoltre non è più ansible passare argomenti.

Un altro modo per farlo è implementare il tuo script come una funzione in bash.

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

Questa tecnica è utilizzata da autojump: http://github.com/joelthelion/autojump/wiki per fornirti i segnalibri della directory di shell di apprendimento.

Questo dovrebbe fare quello che vuoi. Passare alla directory di interesse (all’interno dello script), quindi creare una nuova shell bash.

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

Se lo esegui, ti porterà alla directory di tuo interesse e quando uscirai ti ricondurrà al luogo originale.

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

Questo ti porterà anche alla tua directory originale quando esci ( CTRL + d )

LOOOOOng tempo dopo, ma ho fatto quanto segue:

crea un file chiamato case

incolla quanto segue nel file:

 #!/bin/sh cd /home/"$1" 

salvalo e poi:

 chmod +x case 

Ho anche creato un alias nel mio .bashrc :

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

ora quando scrivo:

 case 12345 

essenzialmente sto scrivendo:

 cd /home/12345 

Puoi digitare qualsiasi cartella dopo “caso”:

 case 12 case 15 case 17 

che è come digitare:

 cd /home/12 cd /home/15 cd /home/17 

rispettivamente

Nel mio caso il percorso è molto più lungo – questi ragazzi lo hanno riassunto con le ~ informazioni precedenti.

Puoi creare una funzione come sotto nel tuo .bash_profile e funzionerà senza intoppi.

La seguente funzione accetta un parametro opzionale che è un progetto. Ad esempio, puoi semplicemente correre

 cdproj 

o

 cdproj project_name 

Ecco la definizione della funzione.

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

Non dimenticarti di .bash_profile tuo .bash_profile

Se si utilizza il pesce come shell, la soluzione migliore è creare una funzione. Ad esempio, data la domanda originale, è ansible copiare le 4 righe seguenti e incollarle nella riga di comando del pesce:

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

Questo creerà la funzione e la salverà per l’uso in un secondo momento. Se il progetto cambia, basta ripetere il processo usando il nuovo percorso.

Se si preferisce, è ansible aggiungere manualmente il file di funzione attenendosi alla seguente procedura:

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

e inserisci il testo:

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

e infine premere ctrl + x per uscire e y seguito da ritorno per salvare le modifiche.

( NOTA: il primo metodo di utilizzo di funcsave crea il file proj.fish per te ).

Ho un semplice script bash chiamato p per gestire la modifica delle directory
github.com/godzilla/bash-stuff
basta mettere lo script nella directory bin locale (/ usr / local / bin)
e metti

 alias p='. p' 

nel tuo .bashrc

Non hai bisogno di script, solo impostare l’opzione corretta e creare una variabile di ambiente.

 shopt -s cdable_vars 

nel tuo ~/.bashrc permette di eseguire il cd sul contenuto delle variabili di ambiente.

Crea una tale variabile d’ambiente:

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

e puoi usare:

 cd myjava 

Altre alternative

Utilizzo delle funzioni di profilo Bash:

Una caratteristica del profilo bash è quella di memorizzare le funzioni personalizzate che possono essere eseguite nel terminale o negli script di bash nello stesso modo in cui si eseguono i comandi / applicazioni, anche questo potrebbe essere usato come scorciatoia per comandi lunghi.

Per rendere ampiamente efficiente il tuo sistema di funzioni dovrai copiare la tua funzione alla fine di diversi file

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

Puoi sudo kwrite /home/user/.bashrc /home/user/.bash_profile /root/.bashrc /root/.bash_profile per modificare / creare rapidamente quei file

Esempio di script

Fare collegamento a cd .. con cdd

 cdd() { cd .. } 

La scorciatoia

 ll() { ls -l -h } 

La scorciatoia

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

Come :

Copia la tua funzione alla fine dei tuoi file e riavvia il tuo terminale, quindi esegui cdd o qualunque sia la funzione che hai scritto

Nota la discussione Come imposto la directory di lavoro del processo genitore?

Contiene alcune risposte hacker, ad esempio https://stackoverflow.com/a/2375174/755804 (modifica della directory del processo principale tramite gdb, non farlo) e https://stackoverflow.com/a/51985735/755804 ( il comando tailcd che inietta cd dirname al stream di input del processo padre, beh, idealmente dovrebbe essere una parte di bash piuttosto che un hack)

È ansible eseguire alcune linee nella stessa subshell se si terminano le righe con backslash.

 cd somedir; \ pwd