Rozumiem, że ls -R
wyświetla listę katalogów. Ale dlaczego jest rekurencyjny? Jak w tym procesie wykorzystywana jest rekurencja?
command-line
ls
Mint.K
źródło
źródło
ls
napotkaniu katalogu rekursywnie wyświetla ten katalog.Odpowiedzi:
Po pierwsze, zdefiniujmy dowolną strukturę folderów:
Gdy to zrobimy
ls
, otrzymamy tylko dane wyjściowe folderu podstawowego:Jednak kiedy dzwonimy
ls -R
, otrzymujemy coś innego:Jak widać, działa
ls
w folderze podstawowym, a następnie we wszystkich folderach podrzędnych. I wszystkie foldery wnuka, ad infinitum. W efekcie polecenie rekurencyjnie przechodzi przez każdy folder, aż dotrze do końca drzewa katalogów. W tym momencie wraca do gałęzi drzewa i robi to samo dla wszystkich podfolderów, jeśli takie istnieją.Lub w pseudokodzie:
A ponieważ mogę, referencyjna implementacja Java tego samego.
źródło
W efekcie możesz zadać dwa ściśle powiązane pytania.
ls
? Z twojego sformułowania („W jaki sposób rekursja jest wykorzystywana w tym procesie?”), Myślę, że jest to część tego, co chcesz wiedzieć. Ta odpowiedź odpowiada na to pytanie.Dlaczego warto
ls
zastosować technikę rekurencyjną:FOLDOC definiuje rekurencję jako:
Naturalnym sposobem implementacji
ls
jest napisanie funkcji, która konstruuje listę pozycji systemu plików, które mają zostać wyświetlone, oraz innego kodu do przetwarzania argumentów ścieżki i opcji oraz do wyświetlania pozycji według potrzeb. Jest wysoce prawdopodobne, że ta funkcja zostanie zaimplementowana rekurencyjnie.Podczas przetwarzania opcji
ls
określi, czy został poproszony o działanie rekurencyjne (przez wywołanie z-R
flagą). Jeśli tak, funkcja, która tworzy listę wpisów do wyświetlenia, wywoła się jeden raz dla każdego katalogu, który zawiera, z wyjątkiem.
i..
. Mogą istnieć osobne wersje rekurencyjne i nierekurencyjne tej funkcji lub funkcja może za każdym razem sprawdzać, czy ma działać rekurencyjnie.Ubuntu
/bin/ls
, plik wykonywalny, który działa podczas uruchamianials
, jest dostarczany przez GNU Coreutils i ma wiele funkcji. W rezultacie jego kod jest nieco dłuższy i bardziej skomplikowany niż można się spodziewać. Ale Ubuntu zawiera również prostszą wersjęls
, dostarczoną przez BusyBox . Możesz uruchomić to, piszącbusybox ls
.Jak
busybox ls
wykorzystuje rekurencję:ls
w BusyBox jest zaimplementowany wcoreutils/ls.c
. Zawierascan_and_display_dirs_recur()
funkcję wywoływaną w celu rekurencyjnego drukowania drzewa katalogów:Linia, w której odbywa się wywołanie funkcji rekurencyjnej, to:
Obserwowanie wywoływanych funkcji rekurencyjnych:
Możesz zobaczyć, jak działa, jeśli uruchomisz
busybox ls
debugger. Najpierw zainstaluj symbole debugowania , włączając pakiety -dbgsym.ddeb, a następnie instalującbusybox-static-dbgsym
pakiet. Zainstalujgdb
również (to jest debugger).Sugeruję debugowanie
coreutils ls
w prostym drzewie katalogów.Jeśli nie masz jednej poręcznej, stwórz ją (działa to tak samo jak
mkdir -p
polecenie w odpowiedzi WinEunuuchs2Unix ):I wypełnij go niektórymi plikami:
Możesz zweryfikować
busybox ls -R foo
prace zgodnie z oczekiwaniami, generując ten wynik:Otwórz
busybox
w debuggerze:GDB wydrukuje niektóre informacje o sobie. To powinno powiedzieć coś takiego:
(gdb)
jest twój monit w debuggerze. Pierwszą rzeczą, którą powiesz GDB, aby zrobiła to w tym monicie, jest ustawienie punktu przerwania na początkuscan_and_display_dirs_recur()
funkcji:Kiedy to uruchomisz, GDB powinien powiedzieć ci coś takiego:
Teraz powiedz GDB, aby działał
busybox
z (lub jakąkolwiek nazwą katalogu) jako argumentami:ls -R foo
Możesz zobaczyć coś takiego:
Jeśli widzisz
No such file or directory
, jak wyżej, to w porządku. Celem tej demonstracji jest tylko sprawdzenie, kiedyscan_and_display_dirs_recur()
funkcja została wywołana, więc GDB nie musi sprawdzać faktycznego kodu źródłowego.Zauważ, że debugger osiągnął punkt przerwania nawet przed wydrukowaniem jakichkolwiek pozycji katalogu. Łamie na wejscie do tej funkcji, ale kod w tej funkcji musi działać na wszystkie katalogi mają być wyliczone przy drukowaniu.
Aby powiedzieć GDB, aby kontynuował, uruchom:
Za każdym razem, gdy
scan_and_display_dirs_recur()
zostanie wywołane, punkt przerwania zostanie ponownie trafiony, dzięki czemu zobaczysz rekurencję w akcji. Wygląda to tak (w tym(gdb)
monit i twoje polecenia):Funkcja ma
recur
w nazwie ... czy BusyBox używa jej tylko wtedy, gdy-R
podana jest flaga? W debuggerze łatwo to znaleźć:Nawet bez
-R
tej konkretnej implementacjils
używa tej samej funkcji, aby dowiedzieć się, jakie wpisy systemu plików istnieją i je wyświetlić.Kiedy chcesz wyjść z debuggera, po prostu powiedz:
Skąd
scan_and_display_dirs_recur()
wie, czy powinien się nazywać:W szczególności, jak to działa inaczej po przekazaniu
-R
flagi? Analiza kodu źródłowego (która może nie być dokładną wersją w systemie Ubuntu) ujawnia, że sprawdza wewnętrzną strukturę danychG.all_fmt
, w której przechowuje opcje , z którymi został wywołany:(Jeśli BusyBox został skompilowany bez obsługi
-R
, to również nie będzie próbował rekurencyjnie wyświetlać wpisów systemu plików; o to chodzi w tejENABLE_FEATURE_LS_RECURSIVE
części.)Tylko wtedy, gdy
G.all_fmt & DISP_RECURSIVE
jest to prawda, uruchamiany jest kod zawierający rekurencyjne wywołanie funkcji.W przeciwnym razie funkcja jest uruchamiana tylko raz (dla katalogu określonego w wierszu poleceń).
źródło
Kiedy się nad tym zastanowić, „rekurencyjne” ma sens dla poleceń, które działają na katalogi i ich pliki i katalogi oraz ich pliki i katalogi oraz ich pliki i katalogi i ich pliki .........
.... dopóki całe drzewo od określonego punktu w dół nie będzie obsługiwane przez komendę, w tym przypadku wyświetlając zawartość wszystkich podkatalogów dowolnych podkatalogów dowolnych podkatalogów .......... argument (y) polecenia
źródło
-R służy do rekurencji, którą można luźno nazwać „wielokrotnie”.
Weźmy na przykład ten kod:
-p
W tworzeniu katalogów pozwala na masowe tworzenie katalogów za pomocą jednego polecenia. Jeśli istnieje już jeden lub więcej górnych środkowych katalogów, nie oznacza to błędu i tworzone są środkowe dolne katalogi.Następnie
ls -R
rekurencyjnie wyświetla każdy katalog zaczynający się od temp i działający w dół drzewa do wszystkich gałęzi.Teraz spójrzmy na uzupełnienie
ls -R
polecenia, tj.tree
Polecenie:Jak widać
tree
osiąga się to samo, cols -R
z wyjątkiem tego, że jest bardziej zwięzłe i ośmielę się powiedzieć „ładniejsze”.Teraz spójrzmy, jak rekurencyjnie usuwać katalogi, które właśnie utworzyliśmy za pomocą jednego prostego polecenia:
To rekurencyjnie usuwa
temp
i wszystkie podkatalogi poniżej. tzntemp/a
,temp/b/1
atemp/c/1/2
także środkowe katalogi pomiędzy.źródło
tree
. To świetne narzędzie.Oto proste wyjaśnienie, które ma sens, ponieważ jeśli chodzi o wyświetlanie zawartości podkatalogów, ta sama funkcja już wie, co zrobić z katalogiem. Dlatego po prostu musi wywołać się w każdym podkatalogu, aby uzyskać ten wynik!
W pseudokodzie wygląda to tak:
źródło