Navigazione veloce tra directory: pushd, popd e dirs

Da Guide@Debianizzati.Org.

Debian-swirl.png Versioni Compatibili
Tutte le versioni supportate di Debian

Indice

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.

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

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.

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.

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

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

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.

il contenuto dello stack viene mostrato su più righe. Ciascuna riga contiene una directory.

come "dirs -p". In più ciascuna riga è contraddistinta da un numero intero che corrisponde all'indice della directory nello stack.

come dirs senza opzioni, la differenza è l'espansione del carattere "~" che viene sostituito con il percorso assoluto dell'home directory.

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.

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 mostrata 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 (caricato a ogni avvio di bash) e poi eseguire un:

$ . .bashrc

per rendere effettive fin da subito 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.




Guida scritta da: S3v

Swirl-auth40.png Debianized 40%

Estesa da:
Verificata da:
HAL 9000 20:17, 20 giu 2014 (CEST)

Verificare ed estendere la guida | Cos'è una guida Debianized

Strumenti personali
Namespace
Varianti
Azioni
Navigazione
Risorse
Strumenti