Cum să parcurgeți un arbore de director pe Linux

Publicat: 2022-07-21
Laptop Linux afișează un prompt bash
fatmawati achmad zaenuri/Shutterstock.com

Directoarele de pe Linux vă permit să grupați fișiere în colecții distincte, separate. Dezavantajul este că devine obositoare trecerea de la un director la altul pentru a efectua o sarcină repetitivă. Iată cum să automatizezi asta.

Totul despre directoare

Prima comandă pe care o înveți când ești introdus în Linux este probabil ls , dar cd nu va fi cu mult în urmă. Înțelegerea directoarelor și a modului de deplasare în jurul lor, în special subdirectoarele imbricate, este o parte fundamentală a înțelegerii modului în care Linux se organizează și a modului în care vă puteți organiza propria lucrare în fișiere, directoare și subdirectoare.

Structura directorului Linux, explicată
LEGATE Structura directorului Linux, explicată

Înțelegerea conceptului de arbore de directoare – și a modului de deplasare între ele – este una dintre multele etape mici pe care le treceți pe măsură ce vă familiarizați cu peisajul Linux. Folosind cd cu o cale te duce la acel director. Comenzile rapide precum cd ~ sau cd singure vă duc înapoi la directorul dvs. de acasă, iar cd .. vă mută la un nivel sus în arborele de directoare. Simplu.

Cu toate acestea, nu există un mijloc la fel de simplu de a rula o comandă în toate directoarele unui arbore de directoare. Există diferite moduri în care putem obține această funcționalitate, dar nu există o comandă Linux standard dedicată acestui scop.

Unele comenzi, cum ar fi ls , au opțiuni de linie de comandă care le forțează să opereze recursiv , ceea ce înseamnă că încep într-un singur director și lucrează metodic prin întregul arbore de directoare de sub acel director. Pentru ls , este opțiunea -R (recursivă).

Dacă trebuie să utilizați o comandă care nu acceptă recursiunea, trebuie să furnizați singur funcționalitatea recursivă. Iată cum să faci asta.

RELATE: 37 de comenzi Linux importante pe care ar trebui să le cunoașteți

Comanda arborelui

Comanda tree nu ne va ajuta cu sarcina la îndemână, dar face mai ușor să vedem structura unui arbore de directoare. Desenează arborele într-o fereastră de terminal, astfel încât să putem obține o imagine de ansamblu instantanee a directoarelor și subdirectoarelor care alcătuiesc arborele de directoare și a pozițiilor lor relative în arbore.

Va trebui să instalați tree .

Pe Ubuntu trebuie să tastați:

 arborele de instalare sudo apt 

Instalarea arborelui pe Ubuntu

Pe Fedora, utilizați:

 sudo dnf install tree 

Instalarea arborelui pe Fedora

Pe Manjaro, comanda este:

 sudo pacman -Sy tree 

Instalarea arborelui pe Manjaro

Utilizarea tree fără parametri scoate arborele de sub directorul curent.

 copac 

Arborele care rulează în directorul curent

Puteți trece o cale către tree pe linia de comandă.

 munca în copaci 

Arbore care rulează într-un director specificat

Opțiunea -d (directoare) exclude fișierele și arată doar directoare.

 tree -d lucru 

Arborele rulează și afișează numai directoare

Acesta este cel mai convenabil mod de a obține o vedere clară a structurii unui arbore de directoare. Arborele de directoare prezentat aici este cel folosit în exemplele următoare. Există cinci fișiere text și opt directoare.

Nu analizați rezultatul de la ls pentru a traversa directoare

Primul tău gând ar putea fi, dacă ls poate traversa în mod recursiv un arbore de directoare, de ce să nu folosești ls pentru a face tocmai asta și să conducă rezultatul în alte comenzi care analizează directoarele și efectuează unele acțiuni?

Analizarea rezultatelor lui ls este considerată o practică proastă. Datorită capacității Linux de a crea nume de fișiere și directoare care conțin tot felul de caractere ciudate, devine foarte dificil să se creeze un parser generic, universal corect.

S-ar putea să nu creați niciodată cu bună știință un nume de director atât de absurd ca acesta, dar o greșeală într-un script sau o aplicație ar putea.

Un nume de director bizar

Analizarea numelor de fișiere și directoare legitime, dar prost luate în considerare este predispusă la erori. Există și alte metode pe care le putem folosi, care sunt mai sigure și mult mai robuste decât ne bazam pe interpretarea rezultatului lui ls .

Folosind comanda find

Comanda find are capabilități recursive încorporate și, de asemenea, are capacitatea de a rula comenzi pentru noi. Acest lucru ne permite să construim o singură linie puternică. Dacă este ceva pe care probabil că veți dori să îl utilizați în viitor, vă puteți transforma linerul într-un alias sau într-o funcție shell.

Această comandă circulă recursiv prin arborele de directoare, căutând directoare. De fiecare dată când găsește un director, tipărește numele directorului și repetă căutarea în acel director. După ce a finalizat căutarea într-un director, iese din acel director și reia căutarea în directorul părinte.

 find work -type d -execdir echo "In:" {} \; 

folosind comanda find pentru a găsi în mod recursiv directoare

Puteți vedea după ordinea în care sunt listate directoarele, cum progresează căutarea prin arbore. Comparând ieșirea de la comanda tree cu ieșirea de la find one-liner, veți vedea cum find caută fiecare director și subdirector pe rând până când ajunge într-un director fără subdirectoare. Apoi merge înapoi la un nivel și reia căutarea la acel nivel.

Iată cum este alcătuită comanda.

  • find : Comanda find .
  • lucru : directorul în care începe căutarea. Aceasta poate fi o cale.
  • -type d : Căutăm directoare.
  • -execdir : Vom executa o comandă în fiecare director pe care îl găsim.
  • echo „În:” {} : Aceasta este comanda., Pur și simplu trimitem ecou numele directorului în fereastra terminalului. „{}” conține numele directorului curent.
  • \; : Acesta este un punct și virgulă folosit pentru a termina comanda. Trebuie să scăpăm cu bara oblică inversă, astfel încât Bash să nu-l interpreteze direct.

Cu o ușoară modificare, putem face ca comanda find să returneze fișiere care se potrivesc cu un indiciu de căutare. Trebuie să includem opțiunea -name și un indiciu de căutare. În acest exemplu, căutăm fișiere text care se potrivesc cu „*.txt” și căutăm numele lor în fereastra terminalului.

 find work -name "*.txt" -type f -execdir echo "Găsit:" {} \; 

folosind comanda find pentru a găsi recursiv fișiere

Dacă căutați fișiere sau directoare depinde de ceea ce doriți să obțineți. Pentru a rula o comandă în fiecare director , utilizați -type d . Pentru a rula o comandă pe fiecare fișier care se potrivește , utilizați -type f .

Această comandă numără liniile din toate fișierele text din directorul de pornire și subdirectoare.

 găsiți lucru -nume "*.txt" -type f -execdir wc -l {} \; 

Folosind find cu comanda wc

LEGATE: Cum să utilizați comanda find în Linux

Parcurgerea arborilor de directoare cu un script

Dacă trebuie să traversați directoare în interiorul unui script, puteți utiliza comanda find în interiorul scriptului. Dacă trebuie – sau doar doriți – să faceți singur căutările recursive, puteți face și asta.

 #!/bin/bash

shopt -s dotglob nullglob

function recursive {

  local current_dir dir_or_file

  pentru curent_dir în $1; do

    echo "Comandă director pentru:" $current_dir

    pentru dir_or_file în „$current_dir”/*; do

      if [[ -d $dir_or_file ]]; apoi
        recursiv „$dir_or_file”
      altfel
        wc $dir_or_file
      fi
    Terminat
  Terminat
}

recursiv „$1”

Copiați textul într-un editor și salvați-l ca „recurse.sh”, apoi utilizați comanda chmod pentru a-l face executabil.

 chmod +x recurs.sh 

Faceți executabil scriptul recurse.sh

Scriptul stabilește două opțiuni de shell, dotglob și nullglob .

Setarea dotglob înseamnă nume de fișiere și directoare care încep cu un punct „ . ” va fi returnat atunci când termenii de căutare cu caractere wildcard sunt extinși. Acest lucru înseamnă efectiv că includem fișiere și directoare ascunse în rezultatele căutării noastre.

Setarea nullglob înseamnă că modelele de căutare care nu găsesc niciun rezultat sunt tratate ca un șir gol sau nul. Ele nu folosesc implicit termenul de căutare în sine. Cu alte cuvinte, dacă căutăm totul dintr-un director folosind caracterul metalic asterisc „ * ”, dar nu există rezultate, vom primi un șir nul în loc de un șir care conține un asterisc. Acest lucru împiedică scriptul să încerce din neatenție să deschidă un director numit „*” sau să trateze „*” ca un nume de fișier.

Apoi, definește o funcție numită recursive . Aici se întâmplă lucrurile interesante.

Sunt declarate două variabile, numite current_dir și dir_or_file . Acestea sunt variabile locale și pot fi referite numai în cadrul funcției.

O variabilă numită $1 este, de asemenea, utilizată în cadrul funcției. Acesta este primul (și singurul) parametru transmis funcției atunci când este apelată.

Primer: Bash Loops: for, while, and until
Primer înrudit: Buclele Bash: for, while, and until

Scriptul folosește două bucle for , una imbricată în cealaltă. Prima buclă for (exterioară) este folosită pentru două lucruri.

Una este să rulați orice comandă pe care doriți să o efectuați în fiecare director. Tot ceea ce facem aici este să redăm numele directorului în fereastra terminalului. Desigur, puteți utiliza orice comandă sau secvență de comenzi sau puteți apela o altă funcție de script.

Al doilea lucru pe care îl face bucla for externă este să verifice toate obiectele sistemului de fișiere pe care le poate găsi - care vor fi fie fișiere, fie directoare. Acesta este scopul buclei for interior. La rândul său, fiecare nume de fișier sau director este trecut în variabila dir_or_file .

Variabila dir_or_file este apoi testată într-o instrucțiune if pentru a vedea dacă este un director.

  • Dacă este, funcția se autoapelează și transmite numele directorului ca parametru.
  • Dacă variabila dir_or_file nu este un director, atunci trebuie să fie un fișier. Orice comandă pe care doriți să le aplicați fișierului poate fi apelată din clauza else a instrucțiunii if . De asemenea, puteți apela o altă funcție în cadrul aceluiași script.

Linia finală din script apelează funcția recursive și trece în primul parametru de linie de comandă $1 ca director de pornire în care să căutați. Acesta este ceea ce declanșează întregul proces.

Să rulăm scriptul.

 ./recurse.sh lucru 

Procesarea directoarelor de la cel mai adânc la cel mai adânc

Directoarele sunt parcurse, iar punctul din script în care ar fi rulată o comandă în fiecare director este indicat de liniile „Comandă director pentru:”. Fișierele găsite au comanda wc rulată pe ele pentru a număra liniile, cuvintele și caracterele.

Primul director procesat este „work”, urmat de fiecare ramură de director imbricată a arborelui.

Un punct interesant de remarcat este că puteți schimba ordinea în care sunt procesate directoarele, mutând comenzile specifice directorului de la a fi deasupra buclei for interioare la a fi sub aceasta.

Să mutăm linia „Directory command for:” după terminarea done for interne.

 #!/bin/bash

shopt -s dotglob nullglob

function recursive {

  local current_dir dir_or_file

  pentru curent_dir în $1; do

    pentru dir_or_file în „$current_dir”/*; do

      if [[ -d $dir_or_file ]]; apoi
        recursiv „$dir_or_file”
      altfel
        wc $dir_or_file
      fi

    Terminat

    echo "Comandă director pentru:" $current_dir

  Terminat
}

recursiv „$1”

Acum vom rula scriptul încă o dată.

 ./recurse.sh lucru 

Procesarea directoarelor de la cel mai adânc la cel mai adânc

De data aceasta, directoarele au comenzile aplicate mai întâi de la cele mai profunde niveluri, lucrând înapoi în sus ramurile arborelui. Directorul transmis ca parametru scriptului este procesat ultimul.

Dacă este important să aveți directoare mai profunde procesate mai întâi, așa puteți face acest lucru.

Recursiunea este ciudată

Este ca și cum te-ai suna pe propriul tău telefon și ți-ai lăsa un mesaj pe care să-l spui când te vei întâlni în mod repetat.

Poate fi nevoie de ceva efort înainte să-i înțelegi beneficiile, dar când o vei face, vei vedea că este o modalitate elegantă din punct de vedere programatic de a aborda problemele grele.

LEGATE: Ce este recursiunea în programare și cum o folosiți?