Come attraversare un albero di directory su Linux

Pubblicato: 2022-07-21
Laptop Linux che mostra un prompt bash
fatmawati achmad zaenuri/Shutterstock.com

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.

La struttura della directory di Linux, spiegata
CORRELATI La struttura della directory di Linux, spiegata

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 

Installazione dell'albero su Ubuntu

Su Fedora, usa:

 albero di installazione sudo dnf 

Installazione dell'albero su Fedora

Su Manjaro, il comando è:

 sudo pacman -Sy tree 

Installazione dell'albero su Manjaro

L'uso tree senza parametri estrae l'albero sotto la directory corrente.

 albero 

Albero in esecuzione nella directory corrente

Puoi passare un percorso tree sulla riga di comando.

 lavoro sugli alberi 

Albero in esecuzione su una directory specificata

L'opzione -d (directory) esclude i file e mostra solo le directory.

 albero -d lavoro 

Albero in esecuzione e mostra solo le directory

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.

Un nome di directory bizzarro

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:" {} \; 

utilizzando il comando find per trovare le directory in modo ricorsivo

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:" {} \; 

utilizzando il comando trova per trovare i file in modo ricorsivo

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 {} \; 

Usando trova con il comando wc

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 

Rendere eseguibile lo script recurse.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.

Primer: Bash Loops: for, while e until
Primer CORRELATO : Bash Loops: for, while e until

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 clausola else dell'istruzione if . 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 

Elaborazione delle directory dal più superficiale al più profondo

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 

Elaborazione delle directory dalla più profonda alla più superficiale

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?