Navigazione veloce tra directory: pushd, popd e dirs
Versioni Compatibili Tutte le versioni supportate di Debian |
Introduzione e funzionamento
Uno degli aspetti più ripetitivi e noiosi quando si lavora spesso su un terminale è quello di doversi spostare con una certa frequenza da una directory di lavoro all'altra per impartire comandi o visualizzare file.
Questi continui spostamenti sono purtroppo non eliminabili ma, almeno, è possibile renderli più veloci nel caso in cui si debba ritornare ad una directory di lavoro già visitata in precedenza o nel caso in cui le directory in cui si lavora siano quasi sempre le stesse.
A questo scopo ci vengono in aiuto tre comandi builtin della shell bash: pushd, popd e dirs.
Il concetto che sta alla base del loro funzionamento è quello di stack (o pila) di directory; è possibile infatti aggiungere o rimuovere directory dallo stack oppure visualizzarne facilmente il contenuto. L'ultima directory aggiunta alla pila finisce in cima allo stack mentre la penultima directory aggiunta diventa la seconda della pila partendo dall'alto e così via. La prima directory aggiunta costituisce la base dello stack e, partendo sempre dall'alto, costituisce l'ultima directory della pila. Un esempio chiarisce meglio il tutto:
$ pushd -n /etc/default $ pushd -n /boot/grub $ pushd -n /var/log $ pushd -n /usr/src
sono state aggiunte allo stack quattro directory, graficamente la situazione è la seguente:
+----------------------+ | | | /usr/src | 1 | | +----------------------+ | | | /var/log | 2 | | +----------------------+ | | | /boot/grub | 3 | | +----------------------+ | | | /etc/default | 4 | | +----------------------+
come si vede, la prima directory inserita è alla base dello stack.
Visualizziamo ora il contenuto dello stack:
$ pwd /home/s3v $ dirs -v 0 ~ 1 /usr/src 2 /var/log 3 /boot/grub 4 /etc/default
possiamo notare come esista un elemento "zero" dello stack in cui è contenuta la directory corrente (nell'esempio precedente è visualizzata tramite il comando pwd
); questo elemento non viene memorizzato permanentemente sullo stack ma cambia ogni volta che ci si sposta in una nuova directory. Esempio:
$ cd /lib $ dirs -v 0 /lib 1 /usr/src 2 /var/log 3 /boot/grub 4 /etc/default $ cd /etc $ dirs -v 0 /etc 1 /usr/src 2 /var/log 3 /boot/grub 4 /etc/default
Per fare in modo che la directory corrente venga memorizzata in cima allo stack, bisogna eseguire esplicitamente il comando:
$ pushd .
Esempio:
$ pwd /etc $ pushd . $ dirs -v 0 /etc 1 /etc 2 /usr/src 3 /var/log 4 /boot/grub 5 /etc/default $ cd /var $ dirs -v 0 /var 1 /etc 2 /usr/src 3 /var/log 4 /boot/grub 5 /etc/default
E se ci siamo accorti che la directory /usr/src
non ci serve più? Niente di più facile:
$ dirs -v 0 /var 1 /etc 2 /usr/src 3 /var/log 4 /boot/grub 5 /etc/default $ popd +2 $ dirs -v 0 /var 1 /etc 2 /var/log 3 /boot/grub 4 /etc/default
con il comando "popd +2
" abbiamo rimosso l'elemento dello stack di indice 2.
A questo punto diventa facilissimo muoversi tra le directory salvate nello stack; infatti, supponendo di volersi posizionare in /etc/default
, basta un:
$ cd ~4
mentre per editare il file /etc/default/grub
:
$ vim ~4/grub
cioè specificando il numero corrispondente ottenuto con il comando "dirs -v
".
Pushd
Il comando pushd
serve per memorizzare una directory in cima allo stack o per ruotare lo stack portandone in cima la directory voluta.
- pushd
my_directory
ci si sposta nella directory my_directory
che diventa "l'elemento zero" dello stack, il precedente elemento zero diventa l'elemento di indice 1 e così via. La directory my_directory
non viene salvata permanentemente sullo stack a meno di non eseguire esplicitamente un "pushd .
"
Questo comando è utile se si vuol salvare permanentemente sullo stack sia la directory di lavoro corrente che la directory my_directory
(quest'ultima dopo aver eseguito un "pushd .
")
In questo esempio la directory my_directory
equivale a /var/log
e la directory di partenza è /etc
:
$ pwd /etc $ dirs -v 0 /etc $ pushd /var/log $ pwd /var/log $ dirs -v 0 /var/log 1 /etc $ pushd . $ dirs -v 0 /var/log 1 /var/log 2 /etc $ cd ~2 $ pwd /etc $ dirs -v 0 /etc 1 /var/log 2 /etc
- pushd -n
my_directory
comando molto simile al precedente tranne che per l'aggiunta dell'opzione "-n" che consente di manipolare solo lo stack senza il cambio di directory visto nel precedente caso.
In questo esempio la directory my_directory
equivale a /tmp/prova
e la directory di partenza è /usr
:
$ pwd /usr $ dirs -v 0 /usr $ pushd -n /tmp/prova $ pwd /usr $ dirs -v 0 /usr 1 /tmp/prova
Questo comando è utile per inserire permanentemente una directory, diversa dalla directory corrente, in cima allo stack. Al termine del comando la directory di lavoro corrente non cambia.
- pushd +num
- pushd -num
Come "pushd my_directory
" tranne per il fatto che la directory individuata da num
appartiene già allo stack. Entrambi i comandi causano una rotazione dello stack; num
è un numero intero che rappresenta la posizione della directory nella pila iniziando a contare dall'alto (+num) o dal basso (-num) partendo sempre da zero.
Esempio 1:
$ pwd /etc $ dirs -v 0 /etc 1 /usr 2 /var/log 3 /lib $ pushd +3 $ pwd /lib $ dirs -v 0 /lib 1 /etc 2 /usr 3 /var/log
Esempio 2:
$ pwd /etc $ dirs -v 0 /etc 1 /usr 2 /var/log 3 /lib $ pushd -2 $ pwd /usr $ dirs -v 0 /usr 1 /var/log 2 /lib 3 /etc
in quest'ultimo esempio si nota come il comando "pushd -2
" individua la directory /usr
in quanto si inizia a contare dal basso a partire dal numero zero.
In entrambi i casi la directory di lavoro diventa quella individuata attraverso num
.
Questi comandi, benché apparentemente scomodi, possono rivelarsi utili nel caso in cui ci si accorga che una directory memorizzata nello stack sia inutile perché contiene directory più specifiche che vale la pena avere a portata di mano; si veda a proposito questo esempio:
$ pwd /usr $ dirs -v 0 /usr 1 /var/log 2 /lib/modules 3 /etc $ pushd +3 $ pwd /etc $ dirs -v 0 /etc 1 /usr 2 /var/log 3 /lib/modules $ pushd default $ pwd /etc/default $ dirs -v 0 /etc/default 1 /etc 2 /usr 3 /var/log 4 /lib/modules $ pushd $ pwd /etc $ dirs -v 0 /etc 1 /etc/default 2 /usr 3 /var/log 4 /lib/modules $ pushd ca-certificates $ pwd /etc/ca-certificates $ dirs -v 0 /etc/ca-certificates 1 /etc 2 /etc/default 3 /usr 4 /var/log 5 /lib/modules $ pushd $ pwd /etc $ dirs -v 0 /etc 1 /etc/ca-certificates 2 /etc/default 3 /usr 4 /var/log 5 /lib/modules
si può inoltre notare come sia possibile specificare percorsi relativi per le directory a partire dalla directory corrente e come si possa effettuare uno swap degli elementi 0 e 1 dello stack attraverso il comando:
$ pushd
eseguito senza argomenti.
- pushd -n +num
- pushd -n -num
A questo punto il risultato di questi due comandi può essere facilmente indovinato: l'opzione "-n" opera direttamente sullo stack senza effettuare nessun cambio di directory di lavoro. Lo stack viene ruotato come nell'esempio precedente ma la directory corrente resta invariata. Questo porta alla cancellazione dalla pila della directory individuata e alla sua sostituzione in cima allo stack dalla directory corrente.
Si veda quest'esempio con directory corrente uguale a /usr/src
:
$ pwd /usr/src $ dirs -v 0 /usr/src 1 /etc/ca-certificates 2 /etc/default 3 /usr 4 /var/log 5 /lib/modules $ pushd -n +4 $ pwd /usr/src $ dirs -v 0 /usr/src 1 /lib/modules 2 /usr/src 3 /etc/ca-certificates 4 /etc/default 5 /usr
come si vede la directory /var/log
è stata portata in cima e poi sostituita dalla directory corrente /usr/src
che non viene cambiata.
Popd
Se il comando pushd
viene utilizzato per memorizzare directory sullo stack, il suo duale popd
serve per rimuovere directory. Lanciato senza argomenti, si sposta nella directory di indice 1 trasformandola in elemento zero dello stack.
Esempio:
$ pwd /var $ dirs -v 0 /var 1 /etc 2 /usr $ popd $ pwd /etc $ dirs -v 0 /etc 1 /usr
- popd -num
- popd +num
Con questi due comandi si rimuove dallo stack la directory voluta mentre la directory corrente di lavoro resta invariata. Il significato del valore num
è uguale a quello spiegato per il comando pushd
.
Esempio:
$ pwd /var $ dirs -v 0 /var 1 /lib/modules 2 /usr/src 3 /etc/ca-certificates 4 /etc/default 5 /usr $ popd +3 $ pwd /var $ dirs -v 0 /var 1 /lib/modules 2 /usr/src 3 /etc/default 4 /usr $ popd -1 $ pwd /var $ dirs -v 0 /var 1 /lib/modules 2 /usr/src 3 /usr
- popd -n
Come popd
senza argomenti tranne per il fatto che la directory corrente resta invariata. In pratica cancella l'elemento di indice 1 dello stack. Ad esempio:
$ pwd /var $ dirs -v 0 /var 1 /lib/modules 2 /usr/src 3 /etc/ca-certificates 4 /etc/default 5 /usr $ popd -n $ pwd /var $ dirs -v 0 /var 1 /usr/src 2 /etc/ca-certificates 3 /etc/default 4 /usr
Dirs
Il comando dirs
elenca il contenuto dello stack delle directory. Lanciato senza opzioni mostra semplicemente il contenuto dello stack su una singola riga.
- dirs -p
il contenuto dello stack viene mostrato su più righe. Ciascuna riga contiene una directory.
- dirs -v
come "dirs -p
". In più ciascuna riga è contraddistinta da un numero intero che corrisponde all'indice della directory nello stack.
- dirs -l
come dirs
senza opzioni, la differenza è l'espansione del carattere "~" che viene sostituito con il percorso assoluto dell'home directory.
- dirs +num
- dirs -num
mostra semplicemente il nome della directory contenuta nello stack e trovata in base all'intero num
. Il significato di num
è lo stesso dei comandi pushd
e popd
.
- dirs -c
svuota lo stack delle directory.
DIRSTACK
Lo stack di directory viene memorizzato nella variabile d'ambiente DIRSTACK, questa variabile è concettualmente un array di stringhe rappresentate dalle directory. I comandi sopra descritti operano in modo da aggiungere, togliere, ruotare o visualizzare gli elementi di questo array.
Per visualizzare questa variabile basta un:
$ echo ${DIRSTACK[@]}
che restituisce il medesimo output del comando dirs
.
Ciscun elemento dell'array è accessibile tramite il suo indice che, ricordiamo, parte dal numero zero. Pertanto i seguenti comandi visualizzeranno il primo e il secondo elemento dello stack di directory:
$ echo ${DIRSTACK[0]} $ echo ${DIRSTACK[1]}
in questo modo, invece, viene mostrato l'ultima directory memorizzata nella pila:
echo ${DIRSTACK[${#DIRSTACK[@]}-1]}
Contenuto di un file sullo stack
Un aspetto negativo del funzionamento dei comandi pushd
, popd
e dirs
è dovuto alla cancellazione dello stack ad ogni chiusura della sessione di terminale o di terminale virtuale, facendo perdere la comodità di avere sempre uno stack contenente le directory preferite tra cui spostarsi.
Per evitare di dover caricare le stesse directory ad ogni avvio di sessione, lavoro decisamente noioso ed evitabile anche nel caso in cui le directory da memorizzare siano poche, è possibile inserire alcune righe nel file .bashrc
:
while read line; do pushd -n "$line" &>/dev/null done < ~/dirstack
questo permetterà, ad ogni avvio di sessione, di ripopolare lo stack con il contenuto del file dirstack
che, in questo esempio, si trova nella nostra home directory.
Questo file contiene una directory per ciascuna sua riga ed è possibile modificarlo a mano oppure salvandoci sopra l'attuale stack di directory:
$ dirs -p -l | tac > ~/dirstack
Directory alla base dello stack
Un caso non tanto raro è quello di avere una lista fissa di directory tra cui muoverci e di aver memorizzato mentalmente i rispettivi indici sullo stack senza far ricorso al comando dirs
; cosa succede, però, se capita di doversi spostare, magari temporaneamente, tra un certo numero di directory diverse?
Succede qualcosa di abbastanza fastidioso: l'inserimento con pushd
delle nuove directory in cima allo stack modifica l'ordine delle directory salvate; questo fa perdere il vantaggio di ricordare l'indice consueto rallentando, quindi, il lavoro.
Qui di seguito viene proposta una semplice funzione, chiamata pushd_rev
, che ha il compito di inserire una directory alla base dello stack anziché in cima. Il vantaggio è quello di non modificare gli indici delle directory precedentemente salvate e ricordate.
pushd_rev() { [ $# -eq 1 -a ${#DIRSTACK[@]} -ne 1 ] || return 1 local tmp i if [ $1 == "." ]; then pushd -n $PWD &>/dev/null elif [ ${1:0:1} != "/" ]; then pushd -n $PWD/$1 &>/dev/null else pushd -n $1 &>/dev/null fi for ((i=1; i<${#DIRSTACK[@]}-1; i++)); do tmp=${DIRSTACK[i]} DIRSTACK[i]=${DIRSTACK[i+1]} DIRSTACK[i+1]=$tmp done dirs return 0 }
È possibile inserire le precedenti righe in .bashrc
e poi eseguire un:
$ . .bashrc
per rendere effettive le modifiche al file.
La funzione accetta un unico argomento (la directory da inserire alla base dello stack) e controlla che lo stack non contenga una sola directory, inoltre, al termine del comando, la directory corrente di lavoro resta invariata. La directory passata come argomento può avere un percorso relativo, un percorso assoluto e può essere uguale a "."
Esempio:
$ pwd /home $ dirs -v 0 /home 1 /etc 2 /var 3 /usr 4 /boot $ pushd_rev /home/pippo $ pushd_rev pluto $ pushd_rev . $ dirs -v 0 /home 1 /etc 2 /var 3 /usr 4 /boot 5 /home/pippo 6 /home/pluto 7 /home
si può vedere come le directory /etc
, /var
, /usr
e /boot
mantengano il loro indice nello stack.