Come attraversare un albero di directory su Linux
Pubblicato: 2022-07-21
Le directory su Linux ti consentono di raggruppare i file in raccolte distinte e separate. Lo svantaggio è che diventa noioso spostarsi da una directory all'altra per eseguire un'attività ripetitiva. Ecco come automatizzarlo.
Tutto sulle directory
Il primo comando che impari quando vieni introdotto a Linux è probabilmente ls
, ma cd
non sarà molto indietro. Comprendere le directory e come spostarle, in particolare le sottodirectory nidificate, è una parte fondamentale per capire come si organizza Linux e come organizzare il proprio lavoro in file, directory e sottodirectory.
Afferrare il concetto di un albero di directory e come spostarsi tra di loro è una delle tante piccole pietre miliari che si superano mentre si familiarizza con il panorama di Linux. L'uso di cd
con un percorso ti porta a quella directory. Scorciatoie come cd ~
o cd
da solo ti riportano alla tua home directory e cd ..
ti fa salire di un livello nell'albero delle directory. Semplice.
Tuttavia, non esiste un mezzo altrettanto semplice per eseguire un comando in tutte le directory di un albero di directory. Esistono diversi modi in cui possiamo ottenere tale funzionalità, ma non esiste un comando Linux standard dedicato a tale scopo.
Alcuni comandi, come ls
, hanno opzioni della riga di comando che li obbligano a operare in modo ricorsivo , il che significa che iniziano in una directory e funzionano metodicamente attraverso l'intero albero di directory al di sotto di quella directory. Per ls
, è l'opzione -R
(ricorsiva).
Se devi usare un comando che non supporta la ricorsione, devi fornire tu stesso la funzionalità ricorsiva. Ecco come farlo.
CORRELATI: 37 importanti comandi Linux che dovresti conoscere
Il comando dell'albero
Il comando tree
non ci aiuterà con l'attività in corso, ma rende facile vedere la struttura di un albero di directory. Disegna l'albero in una finestra di terminale in modo da poter ottenere una panoramica istantanea delle directory e delle sottodirectory che compongono l'albero delle directory e delle loro posizioni relative nell'albero.
Dovrai installare tree
.
Su Ubuntu devi digitare:
sudo apt install tree
Su Fedora, usa:
albero di installazione sudo dnf
Su Manjaro, il comando è:
sudo pacman -Sy tree
L'uso tree
senza parametri estrae l'albero sotto la directory corrente.
albero
Puoi passare un percorso tree
sulla riga di comando.
lavoro sugli alberi
L'opzione -d
(directory) esclude i file e mostra solo le directory.
albero -d lavoro
Questo è il modo più conveniente per avere una visione chiara della struttura di un albero di directory. L'albero delle directory mostrato qui è quello utilizzato nei seguenti esempi. Ci sono cinque file di testo e otto directory.
Non analizzare l'output da ls a Traverse Directory
Il tuo primo pensiero potrebbe essere, se ls
può attraversare ricorsivamente un albero di directory, perché non usare ls
per fare proprio questo e reindirizzare l'output ad altri comandi che analizzano le directory ed eseguono alcune azioni?
L'analisi dell'output di ls
è considerata una cattiva pratica. A causa della capacità in Linux di creare nomi di file e directory contenenti tutti i tipi di strani caratteri, diventa molto difficile creare un parser generico e universalmente corretto.
Potresti non creare mai consapevolmente un nome di directory così assurdo come questo, ma potrebbe esserci un errore in uno script o in un'applicazione.
L'analisi di nomi di file e directory legittimi ma scarsamente considerati è soggetta a errori. Ci sono altri metodi che possiamo usare che sono più sicuri e molto più robusti rispetto all'interpretazione dell'output di ls
.
Usando il comando trova
Il comando find
ha funzionalità ricorsive integrate e ha anche la possibilità di eseguire comandi per noi. Questo ci consente di creare potenti one-liner. Se è qualcosa che probabilmente vorrai usare in futuro, puoi trasformare il tuo one-liner in un alias o in una funzione di shell.
Questo comando scorre ricorsivamente l'albero delle directory, alla ricerca di directory. Ogni volta che trova una directory, stampa il nome della directory e ripete la ricerca all'interno di quella directory. Dopo aver completato la ricerca in una directory, esce da quella directory e riprende la ricerca nella directory principale.
trova lavoro -type d -execdir echo "In:" {} \;
Puoi vedere dall'ordine in cui sono elencate le directory, come procede la ricerca attraverso l'albero. Confrontando l'output del comando tree
con l'output di find
one-liner, vedrai come find
ricerca a turno ogni directory e sottodirectory fino a raggiungere una directory senza sottodirectory. Quindi torna indietro di un livello e riprende la ricerca a quel livello.
Ecco come è composto il comando.
- trova : il comando
find
. - lavoro : la directory in cui iniziare la ricerca. Può essere un percorso.
- -type d : Stiamo cercando directory.
- -execdir : eseguiremo un comando in ogni directory che troviamo.
- echo “In:” {} : Questo è il comando. Stiamo semplicemente riportando il nome della directory alla finestra del terminale. Il "{}" contiene il nome della directory corrente.
- \; : Questo è un punto e virgola utilizzato per terminare il comando. Dobbiamo evitarlo con la barra rovesciata in modo che Bash non lo interpreti direttamente.
Con una leggera modifica, possiamo fare in modo che il comando trova restituisca file che corrispondono a un indizio di ricerca. Dobbiamo includere l'opzione -name e un indizio di ricerca. In questo esempio, stiamo cercando file di testo che corrispondano a "*.txt" e riportiamo il loro nome nella finestra del terminale.

trova lavoro -name "*.txt" -type f -execdir echo "Trovato:" {} \;
Se cerchi file o directory dipende da cosa vuoi ottenere. Per eseguire un comando all'interno di ciascuna directory , utilizzare -type d
. Per eseguire un comando su ogni file corrispondente , utilizzare -type f
.
Questo comando conta le righe in tutti i file di testo nella directory iniziale e nelle sottodirectory.
trova lavoro -name "*.txt" -type f -execdir wc -l {} \;
CORRELATI: Come utilizzare il comando trova in Linux
Attraversare gli alberi delle directory con uno script
Se hai bisogno di attraversare le directory all'interno di uno script, puoi usare il comando find
all'interno del tuo script. Se hai bisogno, o semplicemente vuoi, di fare le ricerche ricorsive da solo, puoi farlo anche tu.
#!/bin/bash shopt -s dotglob nullglob funzione ricorsiva { directory_corrente locale dir_or_file per dir_corrente in $1; fare echo "Comando directory per:" $current_dir per dir_or_file in "$current_dir"/*; fare se [[ -d $dir_o_file ]]; poi ricorsivo "$dir_or_file" altro wc $dir_o_file fi fatto fatto } ricorsivo "$ 1"
Copia il testo in un editor e salvalo come "recurse.sh", quindi usa il comando chmod
per renderlo eseguibile.
chmod +x ricorsione.sh
Lo script imposta due opzioni di shell, dotglob
e nullglob
.
L'impostazione dotglob
indica nomi di file e directory che iniziano con un punto “ .
” verrà restituito quando i termini di ricerca con caratteri jolly vengono espansi. Ciò significa effettivamente che stiamo includendo file e directory nascosti nei nostri risultati di ricerca.
L'impostazione nullglob
significa che i modelli di ricerca che non trovano alcun risultato vengono trattati come una stringa vuota o nulla. Non impostano automaticamente il termine di ricerca stesso. In altre parole, se stiamo cercando tutto in una directory usando il carattere jolly asterisco “ *
“, ma non ci sono risultati riceveremo una stringa nulla invece di una stringa contenente un asterisco. Ciò impedisce allo script di tentare inavvertitamente di aprire una directory denominata “*” o di trattare “*” come un nome file.
Successivamente, definisce una funzione chiamata recursive
. È qui che accadono le cose interessanti.
Vengono dichiarate due variabili, chiamate current_dir
e dir_or_file
. Queste sono variabili locali e possono essere referenziate solo all'interno della funzione.
All'interno della funzione viene utilizzata anche una variabile chiamata $1
. Questo è il primo (e unico) parametro passato alla funzione quando viene chiamata.
Lo script usa due cicli for
, uno annidato dentro l'altro. Il primo ciclo for
(esterno) viene utilizzato per due cose.
Uno è eseguire qualsiasi comando si desidera eseguire in ciascuna directory. Tutto ciò che stiamo facendo qui è riportare il nome della directory nella finestra del terminale. Ovviamente potresti usare qualsiasi comando o sequenza di comandi o chiamare un'altra funzione di script.
La seconda cosa che fa il ciclo for esterno è controllare tutti gli oggetti del file system che riesce a trovare, che saranno file o directory. Questo è lo scopo del ciclo for
interno. A sua volta, ogni nome di file o directory viene passato alla variabile dir_or_file
.
La variabile dir_or_file
viene quindi testata in un'istruzione if per vedere se si tratta di una directory.
- Se lo è, la funzione chiama se stessa e passa il nome della directory come parametro.
- Se la variabile
dir_or_file
non è una directory, deve essere un file. Qualsiasi comando che si desidera applicare al file può essere chiamato dalla clausolaelse
dell'istruzioneif
. Puoi anche chiamare un'altra funzione all'interno dello stesso script.
L'ultima riga dello script chiama la funzione recursive
e passa nel primo parametro della riga di comando $1
come directory iniziale in cui cercare. Questo è ciò che dà il via all'intero processo.
Eseguiamo lo script.
./recurse.sh lavoro
Le directory vengono attraversate e il punto nello script in cui verrebbe eseguito un comando in ciascuna directory è indicato dalle righe "Comando directory per:". I file trovati hanno il comando wc
eseguito su di essi per contare righe, parole e caratteri.
La prima directory elaborata è "lavoro", seguita da ogni ramo di directory nidificato dell'albero.
Un punto interessante da notare è che puoi cambiare l'ordine in cui vengono elaborate le directory, spostando i comandi specifici della directory dall'essere sopra il ciclo for interno a essere sotto di esso.
Spostiamo la riga "Directory command for:" al done
del ciclo for
interno.
#!/bin/bash shopt -s dotglob nullglob funzione ricorsiva { directory_corrente locale dir_or_file per dir_corrente in $1; fare per dir_or_file in "$current_dir"/*; fare se [[ -d $dir_o_file ]]; poi ricorsivo "$dir_or_file" altro wc $dir_o_file fi fatto echo "Comando directory per:" $current_dir fatto } ricorsivo "$ 1"
Ora eseguiremo lo script ancora una volta.
./recurse.sh lavoro
Questa volta le directory hanno i comandi applicati prima dai livelli più profondi, lavorando sui rami dell'albero. La directory passata come parametro allo script viene elaborata per ultima.
Se è importante che le directory più profonde vengano elaborate prima, ecco come puoi farlo.
La ricorsione è strana
È come chiamarti sul tuo stesso telefono e lasciare un messaggio per te stesso da dire a te stesso quando ti incontrerai la prossima volta, ripetutamente.
Può essere necessario uno sforzo prima di coglierne i vantaggi, ma quando lo farai vedrai che è un modo programmaticamente elegante per affrontare problemi difficili.
CORRELATI: Che cos'è la ricorsione nella programmazione e come la usi?