Jak przeszukiwać drzewo katalogów w systemie Linux?

Opublikowany: 2022-07-21
Laptop z systemem Linux wyświetlający monit o bash
fatmawati achmad zaenuri/Shutterstock.com

Katalogi w systemie Linux umożliwiają grupowanie plików w odrębne, oddzielne kolekcje. Minusem jest to, że przechodzenie z katalogu do katalogu w celu wykonania powtarzalnego zadania staje się żmudne. Oto jak to zautomatyzować.

Wszystko o katalogach

Pierwszym poleceniem, którego nauczysz się po zapoznaniu się z Linuksem, jest prawdopodobnie ls , ale cd nie zostanie daleko w tyle. Zrozumienie katalogów i sposobu poruszania się po nich, szczególnie zagnieżdżonych podkatalogów, jest fundamentalną częścią zrozumienia, jak Linux organizuje się i jak możesz organizować własną pracę w pliki, katalogi i podkatalogi.

Wyjaśnienie struktury katalogów w systemie Linux
POWIĄZANE Struktura katalogów systemu Linux, wyjaśniona

Zrozumienie koncepcji drzewa katalogów — i sposobu poruszania się między nimi — jest jednym z wielu małych kamieni milowych, które mijasz, zaznajamiając się z krajobrazem Linuksa. Użycie cd ze ścieżką prowadzi do tego katalogu. Skróty takie jak cd ~ lub cd same zabierają cię z powrotem do twojego katalogu domowego, a cd .. przenosi cię o jeden poziom wyżej w drzewie katalogów. Prosty.

Jednak nie ma równie prostego sposobu na uruchomienie polecenia we wszystkich katalogach drzewa katalogów. Istnieją różne sposoby na osiągnięcie tej funkcjonalności, ale nie ma standardowej komendy Linuksa przeznaczonej do tego celu.

Niektóre polecenia, takie jak ls , mają opcje wiersza poleceń, które zmuszają je do działania rekurencyjnego , co oznacza, że ​​zaczynają się w jednym katalogu i metodycznie przechodzą przez całe drzewo katalogów poniżej tego katalogu. Dla ls jest to opcja -R (rekurencyjna).

Jeśli potrzebujesz użyć polecenia, które nie obsługuje rekurencji, musisz samodzielnie udostępnić funkcję rekurencyjną. Oto jak to zrobić.

POWIĄZANE: 37 ważnych poleceń systemu Linux, które powinieneś znać

Drzewo Polecenie

Polecenie tree nie pomoże nam w bieżącym zadaniu, ale ułatwia zobaczenie struktury drzewa katalogów. Rysuje drzewo w oknie terminala, dzięki czemu możemy uzyskać natychmiastowy przegląd katalogów i podkatalogów, które tworzą drzewo katalogów, oraz ich względne pozycje w drzewie.

Musisz zainstalować tree .

W Ubuntu musisz wpisać:

 drzewo instalacji sudo apt 

Instalowanie drzewa na Ubuntu

W Fedorze użyj:

 drzewo instalacji sudo dnf 

Instalowanie drzewa w Fedorze

Na Manjaro polecenie to:

 sudo pacman -Sy drzewo 

Instalowanie drzewa na Manjaro

Użycie tree bez parametrów rysuje drzewo poniżej bieżącego katalogu.

 drzewo 

Uruchamianie drzewa w bieżącym katalogu

Możesz podać ścieżkę do tree w wierszu poleceń.

 drzewo praca 

Uruchamianie drzewa w określonym katalogu

Opcja -d (katalogi) wyklucza pliki i pokazuje tylko katalogi.

 drzewo -d praca 

Uruchamianie drzewa i wyświetlanie tylko katalogów

Jest to najwygodniejszy sposób uzyskania przejrzystego obrazu struktury drzewa katalogów. Przedstawione tutaj drzewo katalogów jest tym, które zostało użyte w poniższych przykładach. Istnieje pięć plików tekstowych i osiem katalogów.

Nie analizuj danych wyjściowych z ls do katalogów przechodzenia

Twoja pierwsza myśl może brzmieć, jeśli ls może rekursywnie ls drzewo katalogów, dlaczego nie użyć go właśnie do tego i przekazać dane wyjściowe do innych poleceń, które analizują katalogi i wykonują pewne działania?

Parsowanie wyjścia ls jest uważane za złą praktykę. Ze względu na możliwość tworzenia w Linuksie nazw plików i katalogów zawierających różnego rodzaju dziwne znaki, bardzo trudno jest stworzyć ogólny, uniwersalnie poprawny parser.

Być może nigdy świadomie nie stworzysz nazwy katalogu tak niedorzecznej jak ta, ale może to być błąd w skrypcie lub aplikacji.

Dziwna nazwa katalogu

Analizowanie prawidłowych, ale słabo przemyślanych nazw plików i katalogów jest podatne na błędy. Istnieją inne metody, których możemy użyć, które są bezpieczniejsze i znacznie bardziej niezawodne niż poleganie na interpretacji wyniku ls .

Korzystanie z polecenia Znajdź

Polecenie find ma wbudowane funkcje rekurencyjne, a także ma możliwość uruchamiania poleceń za nas. To pozwala nam budować potężne one-linery. Jeśli jest to coś, czego prawdopodobnie będziesz chciał użyć w przyszłości, możesz zmienić swój jednowierszowy w alias lub funkcję powłoki.

To polecenie rekurencyjnie przegląda drzewo katalogów w poszukiwaniu katalogów. Za każdym razem, gdy znajdzie katalog, wypisuje nazwę katalogu i powtarza wyszukiwanie w tym katalogu. Po zakończeniu przeszukiwania jednego katalogu opuszcza ten katalog i wznawia wyszukiwanie w swoim katalogu nadrzędnym.

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

używanie polecenia find do rekursywnego wyszukiwania katalogów

Możesz zobaczyć, w jakiej kolejności katalogi są wymienione, jak przebiega wyszukiwanie w drzewie. Porównując dane wyjściowe polecenia tree z danymi wyjściowymi polecenia find jednowierszowego, zobaczysz, jak find przeszukuje kolejno każdy katalog i podkatalog, aż dotrze do katalogu bez podkatalogów. Następnie cofa się o jeden poziom i wznawia wyszukiwanie na tym poziomie.

Oto jak składa się polecenie.

  • find : polecenie find .
  • work : katalog, w którym rozpocznie się wyszukiwanie. Może to być ścieżka.
  • -type d : szukamy katalogów.
  • -execdir : Zamierzamy wykonać polecenie w każdym znalezionym katalogu.
  • echo „In:” {} : To jest polecenie. Po prostu wyświetlamy nazwę katalogu w oknie terminala. „{}” zawiera nazwę bieżącego katalogu.
  • \; : To jest średnik używany do zakończenia polecenia. Musimy uciec przed nim za pomocą odwrotnego ukośnika, aby Bash nie zinterpretował go bezpośrednio.

Z niewielką zmianą możemy sprawić, że polecenie find zwróci pliki pasujące do wskazówki wyszukiwania. Musimy dołączyć opcję -name i wskazówkę wyszukiwania. W tym przykładzie szukamy plików tekstowych pasujących do „*.txt” i wyświetlamy ich nazwę w oknie terminala.

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

używanie polecenia find do rekursywnego wyszukiwania plików

To, czy szukasz plików, czy katalogów, zależy od tego, co chcesz osiągnąć. Aby uruchomić polecenie w każdym katalogu , użyj -type d . Aby uruchomić polecenie na każdym zgodnym pliku , użyj -type f .

To polecenie zlicza wiersze we wszystkich plikach tekstowych w katalogu początkowym i podkatalogach.

 znajdź pracę -nazwa "*.txt" -type f -execdir wc -l {} \; 

Używanie find z poleceniem wc

POWIĄZANE: Jak korzystać z polecenia find w systemie Linux

Przechodzenie przez drzewa katalogów za pomocą skryptu

Jeśli potrzebujesz przeszukiwać katalogi wewnątrz skryptu, możesz użyć polecenia find wewnątrz skryptu. Jeśli musisz – lub po prostu chcesz – wykonać wyszukiwania rekurencyjne samodzielnie, możesz to zrobić.

 #!/kosz/bash

shopt -s dotglob nullglob

funkcja rekurencyjna {

  lokalny bieżący_katalog katalog_lub_plik

  dla current_dir w $1; robić

    echo "Polecenie katalogu dla:" $current_dir

    dla katalogu_lub_pliku w "$bieżący_katalog"/*; robić

      if [[ -d $katalog_lub_plik ]]; następnie
        rekurencyjne "$katalog_lub_plik"
      w przeciwnym razie
        wc $katalog_lub_plik
      fi
    Gotowe
  Gotowe
}

rekurencyjne "$1"

Skopiuj tekst do edytora i zapisz go jako „recurse.sh”, a następnie użyj polecenia chmod , aby uczynić go wykonywalnym.

 chmod +x recurse.sh 

Uczynienie skryptu recurse.sh wykonywalnym

Skrypt ustawia dwie opcje powłoki, dotglob i nullglob .

Ustawienie dotglob oznacza nazwy plików i katalogów, które zaczynają się od kropki „ . ” zostanie zwrócony po rozwinięciu wyszukiwanych haseł z symbolami wieloznacznymi. Oznacza to, że w naszych wynikach wyszukiwania uwzględniamy ukryte pliki i katalogi.

Ustawienie nullglob oznacza, że ​​wzorce wyszukiwania, które nie znajdują żadnych wyników, są traktowane jako ciąg pusty lub pusty. Nie są one domyślnie używane do samego wyszukiwanego hasła. Innymi słowy, jeśli szukamy wszystkiego w katalogu, używając symbolu wieloznacznego gwiazdki „ * ”, ale nie ma wyników, zamiast ciągu zawierającego gwiazdkę otrzymamy ciąg pusty. Zapobiega to przypadkowemu otwarciu przez skrypt katalogu o nazwie „*” lub potraktowaniu „*” jako nazwy pliku.

Następnie definiuje funkcję o nazwie recursive . Tutaj dzieją się ciekawe rzeczy.

Deklarowane są dwie zmienne o nazwach current_dir i dir_or_file . Są to zmienne lokalne i można się do nich odwoływać tylko w ramach funkcji.

W funkcji używana jest również zmienna o nazwie $1 . Jest to pierwszy (i jedyny) parametr przekazywany do funkcji podczas jej wywołania.

Podkład: Bash Loops: na, czas i do
RELATED Primer: Bash Loops: na, chwilę i do

Skrypt używa dwóch pętli for , jednej zagnieżdżonej w drugiej. Pierwsza (zewnętrzna) pętla for służy do dwóch rzeczy.

Jednym z nich jest uruchomienie dowolnego polecenia, które chcesz wykonać w każdym katalogu. Wszystko, co tutaj robimy, to powtarzanie nazwy katalogu w oknie terminala. Możesz oczywiście użyć dowolnego polecenia lub sekwencji poleceń lub wywołać inną funkcję skryptu.

Drugą rzeczą, jaką robi zewnętrzna pętla for, jest sprawdzenie wszystkich znalezionych obiektów systemu plików — którymi będą pliki lub katalogi. Taki jest cel wewnętrznej pętli for . Z kolei każda nazwa pliku lub katalogu jest przekazywana do zmiennej dir_or_file .

Zmienna dir_or_file jest następnie testowana w instrukcji if w celu sprawdzenia, czy jest to katalog.

  • Jeśli tak, funkcja wywołuje samą siebie i przekazuje nazwę katalogu jako parametr.
  • Jeśli zmienna dir_or_file nie jest katalogiem, to musi być plikiem. Wszelkie polecenia, które chcesz zastosować do pliku, można wywołać z klauzuli else instrukcji if . Możesz również wywołać inną funkcję w tym samym skrypcie.

Ostatnia linia w skrypcie wywołuje funkcję recursive i przekazuje pierwszy parametr wiersza poleceń $1 jako katalog początkowy do przeszukania. To właśnie rozpoczyna cały proces.

Uruchommy skrypt.

 ./recurse.sh praca 

Przetwarzanie katalogów od najpłytszego do najgłębszego

Katalogi są przeszukiwane, a punkt w skrypcie, w którym polecenie zostanie uruchomione w każdym katalogu, jest wskazywany przez wiersze „Polecenie katalogu dla:”. Znalezione pliki mają uruchamiane na nich polecenie wc , aby policzyć wiersze, słowa i znaki.

Pierwszym przetwarzanym katalogiem jest „praca”, po którym następuje każda zagnieżdżona gałąź katalogu drzewa.

Warto zauważyć, że możesz zmienić kolejność przetwarzania katalogów, przenosząc polecenia specyficzne dla katalogu z pozycji powyżej wewnętrznej pętli for na znajdującą się pod nią.

Przenieśmy wiersz „Polecenie do katalogu dla:” za done wewnętrznej pętli for .

 #!/kosz/bash

shopt -s dotglob nullglob

funkcja rekurencyjna {

  lokalny bieżący_katalog katalog_lub_plik

  dla current_dir w $1; robić

    dla katalogu_lub_pliku w "$bieżący_katalog"/*; robić

      if [[ -d $katalog_lub_plik ]]; następnie
        rekurencyjne "$katalog_lub_plik"
      w przeciwnym razie
        wc $katalog_lub_plik
      fi

    Gotowe

    echo "Polecenie katalogu dla:" $current_dir

  Gotowe
}

rekurencyjne "$1"

Teraz ponownie uruchomimy skrypt.

 ./recurse.sh praca 

Przetwarzanie katalogów od najgłębszych do najpłytszych

Tym razem do katalogów stosuje się najpierw polecenia z najgłębszych poziomów, pracując w kopii zapasowej gałęzi drzewa. Katalog przekazany jako parametr do skryptu jest przetwarzany jako ostatni.

Jeśli ważne jest, aby najpierw przetworzyć głębsze katalogi, tak możesz to zrobić.

Rekurencja jest dziwna

To tak, jakby dzwonić do siebie na własny telefon i zostawiać sobie wiadomość, aby powiedzieć sobie, kiedy następnym razem się spotkasz — wielokrotnie.

Może zająć trochę wysiłku, zanim zrozumiesz jego zalety, ale gdy to zrobisz, zobaczysz, że jest to programowo elegancki sposób rozwiązywania trudnych problemów.

POWIĄZANE: Co to jest rekurencja w programowaniu i jak z niej korzystać?