Я так понимаю, что ls -R
отображает список каталогов. Но почему это рекурсивно? Как в процессе используется рекурсия?
command-line
ls
Mint.K
источник
источник
ls
встречает каталог, он рекурсивно перечисляет этот каталог.Ответы:
Прежде всего, давайте определим произвольную структуру папок:
Когда мы это сделаем
ls
, мы получим вывод только базовой папки:Однако когда мы звоним
ls -R
, мы получаем что-то другое:Как видите, он работает
ls
в базовой папке, а затем во всех дочерних папках. И все внуковые папки, до бесконечности. По сути, команда рекурсивно просматривает каждую папку, пока не достигнет конца дерева каталогов. В этот момент он возвращает ветку в дереве и делает то же самое для любых подпапок, если они есть.Или в псевдокоде:
И потому что я могу, эталонная реализация Java того же самого.
источник
По сути, вы можете задать два тесно связанных вопроса.
ls
? Из вашей фразы («Как рекурсия используется в процессе?») Я думаю, что это часть того, что вы хотите знать. Этот ответ отвечает на этот вопрос.Почему имеет смысл
ls
быть реализованным с помощью рекурсивной техники:FOLDOC определяет рекурсию как:
Естественным способом реализации
ls
является написание функции, которая создает список записей файловой системы для отображения и другой код для обработки аргументов пути и параметров и для отображения записей по желанию. Скорее всего, эта функция будет реализована рекурсивно.Во время обработки опции
ls
определит, было ли ей предложено работать рекурсивно (вызывается с-R
флагом). Если это так, функция, которая создает список записей для отображения, будет вызывать себя один раз для каждого каталога, который она перечисляет, кроме.
и..
. Там могут быть отдельные рекурсивные и нерекурсивные версии этой функции, или функция может проверять каждый раз, если она должна работать рекурсивно.Ubuntu
/bin/ls
, исполняемый файл, который запускается при запускеls
, предоставляется GNU Coreutils и имеет много функций. В результате его код несколько длиннее и сложнее, чем вы могли ожидать. Но Ubuntu также содержит более простую версиюls
, предоставленную BusyBox . Вы можете запустить это, набравbusybox ls
.Как
busybox ls
используется рекурсия:ls
в BusyBox реализован вcoreutils/ls.c
. Он содержитscan_and_display_dirs_recur()
функцию, которая вызывается для рекурсивной печати дерева каталогов:Строка, где происходит рекурсивный вызов функции:
Видя рекурсивные вызовы функций по мере их появления:
Вы можете увидеть это в действии, если вы запускаете
busybox ls
в отладчике. Сначала установите символы отладки , включив пакеты -dbgsym.ddeb, а затем установитеbusybox-static-dbgsym
пакет. Установитеgdb
также (это отладчик).Я предлагаю отладку
coreutils ls
на простом дереве каталогов.Если у вас нет одного удобного, сделайте его (это работает так же, как
mkdir -p
команда в ответе WinEunuuchs2Unix ):И заполните его некоторыми файлами:
Вы можете проверить
busybox ls -R foo
работоспособность, как и ожидалось, выдав такой вывод:Откройте
busybox
в отладчике:GDB напечатает некоторую информацию о себе. Тогда это должно сказать что-то вроде:
(gdb)
это ваша подсказка в отладчике. Первое, что вы скажете GDB сделать в этом приглашении, это установить точку останова в началеscan_and_display_dirs_recur()
функции:Когда вы запускаете это, GDB должен сказать вам что-то вроде:
Теперь скажите GDB работать
busybox
с (или любым другим именем каталога) в качестве аргументов:ls -R foo
Вы можете увидеть что-то вроде этого:
Если вы видите
No such file or directory
, как указано выше, это нормально. Цель этой демонстрации - просто посмотреть, когдаscan_and_display_dirs_recur()
была вызвана функция, поэтому GDB не нужно проверять фактический исходный код.Обратите внимание, что отладчик достиг точки останова еще до того, как были напечатаны какие-либо записи каталога. Это нарушает вход в эту функцию, но код в этой функции должен выполняться для любых каталогов, перечисляемых для печати.
Чтобы сказать GDB продолжить, запустите:
Каждый раз, когда
scan_and_display_dirs_recur()
вызывается, точка останова будет снова нажата, так что вы увидите рекурсию в действии. Это выглядит так (включая(gdb)
подсказку и ваши команды):Функция имеет
recur
свое имя ... BusyBox использует ее только при-R
заданном флаге? В отладчике это легко узнать:Даже без
-R
, эта конкретная реализацияls
использует ту же функцию, чтобы выяснить, какие записи файловой системы существуют и показать их.Если вы хотите выйти из отладчика, просто скажите это:
Как
scan_and_display_dirs_recur()
узнать, должен ли он называть себя:В частности, как это работает по-другому, когда
-R
флаг передается? Изучение исходного кода (который может быть не точной версией в вашей системе Ubuntu) показывает, что он проверяет свою внутреннюю структуру данныхG.all_fmt
, где хранит параметры, с которыми он был вызван:(Если BusyBox был скомпилирован без поддержки
-R
, то он также не будет пытаться рекурсивно отображать записи файловой системы; в этом сутьENABLE_FEATURE_LS_RECURSIVE
части.)Только когда
G.all_fmt & DISP_RECURSIVE
true, код, содержащий рекурсивный вызов функции, запускается.В противном случае функция запускается только один раз (для каждого каталога, указанного в командной строке).
источник
Когда вы думаете об этом, «рекурсивный» имеет смысл для команд, которые действуют на каталоги и их файлы и каталоги, а также их файлы и каталоги, их файлы и каталоги и их файлы .........
.... до тех пор, пока команда не оперирует всем деревом с указанной точки вниз, в этом случае перечисляется содержимое любых подкаталогов любых подкаталогов любых подкаталогов .........., которые существуют под аргумент (ы) команды
источник
-R для рекурсии, которую можно было бы назвать «неоднократно».
Возьмите этот код для примера:
Создание
-p
каталогов позволяет массово создавать каталоги с помощью одной команды. Если один или несколько каталогов верхнего среднего уровня уже существуют, это не является ошибкой, и каталоги среднего нижнего уровня создаются.Затем
ls -R
рекурсивно перечисляется каждый каталог, начиная с temp и работая вниз по дереву до всех веток.Теперь давайте посмотрим на дополнение к
ls -R
команде, то естьtree
команду:Как вы видите,
tree
выполняет то же, что иls -R
за исключением, является более кратким, и я смею говорить «красивее».Теперь давайте посмотрим, как рекурсивно удалять каталоги, которые мы только что создали, одной простой командой:
Это рекурсивно удаляет
temp
и все подкаталоги под ним. то естьtemp/a
,temp/b/1
иtemp/c/1/2
плюс средние каталоги между ними.источник
tree
хотя. Это отличный инструмент.Вот простое объяснение, это имеет смысл, потому что когда дело доходит до отображения содержимого подкаталогов, та же самая функция уже знает, что делать с каталогом. Поэтому для получения такого результата просто нужно вызвать себя в каждом подкаталоге!
В псевдокоде это выглядит примерно так:
источник