2010-01-28 2 views
9

Я знаю, что вы можете использовать команду find для этой простой работы. Но у меня есть задание не использовать find или ls и выполнять эту работу. Пожалуйста, помогите ....Как рекурсивно перечислить подкаталоги в bash без использования команд find или ls?

+0

Что вы должны использовать для этого? Ваш собственный сценарий оболочки, программа на C, Java ...? Если вы сообщите нам, что вы * можете использовать *, помощь должна быть более прибыльной :-) – Grundlefleck

+0

Возможно, вы сможете использовать 'echo *' или варианты для эмуляции 'ls'. –

ответ

1

Команда du будет перечислять подкаталоги рекурсивно.

Я не уверен, если пустые каталоги получить упоминания, хотя

+0

пустые каталоги отображаются для меня с помощью bash на моем mac –

10

Попробуйте использовать

tree -d 
+1

Почему я получил -1? Прокомментируйте пожалуйста. –

+0

Я не дал вам -1, но для меня это очевидно, почему вы его получили. Почему бы не дать ответ «alias bla ls»; bla'? Заданный вопрос заключался в том, чтобы написать алгоритм, а не найти некоторую * команду *, которая делает то же самое, что и 'ls', но не называется' ls'. – vladr

+7

@ Vlad Romascanu: О, хорошо, но из «У меня есть задание не использовать find или ls и выполнять работу». Я понял, что все было достаточно хорошо, кроме find и ls ^^ –

1

Как Марк Байерс сказал, что вы можете использовать echo *, чтобы получить список всех файлов в текущем каталог.

Команда test или [] имеет возможность проверить, является ли файл каталогом.

Применить рекурсию, и все готово.

+1

В качестве альтернативы' echo', 'for' будет glob , поэтому OP может использовать 'for file in *; делать ... ; done'. – outis

25

вы можете сделать это только с оболочкой

#!/bin/bash 
recurse() { 
for i in "$1"/*;do 
    if [ -d "$i" ];then 
     echo "dir: $i" 
     recurse "$i" 
    elif [ -f "$i" ]; then 
     echo "file: $i" 
    fi 
done 
} 

recurse /path 

ИЛИ если у вас есть Баш 4,0

#!/bin/bash 
shopt -s globstar 
for file in /path/** 
do 
    echo $file 
done 
+1

Почему бы вам не сделать так, чтобы вы с помощью команды tree тоже? или тот, у кого есть эхо, это также действительные ответы. – ghostdog74

+0

Это не удастся, если каталог пуст, то есть он будет печатать 'dir: bla/*', поскольку 'bla/*' рассматривается как литерал, поскольку у него нет потомков. Вы можете использовать 'pushd/popd' или добавить' if [["$ 1/*" = "$ i"]]; затем продолжить; fi' как первая строка после 'do'. – Bogdan

0
$ function f { for i in $1/*; do if [ -d $i ]; then echo $i; f $i; fi; done } 
$ mkdir -p 1/2/3 2/3 3 
$ f . 
./1 
./1/2 
./1/2/3 
./2 
./2/3 
./3 
+1

-1 Если вы собираетесь предоставить полный ответ на вопрос о домашнем задании, сделайте его правильным. как насчет пробелов в именах записей в каталоге? –

+0

, и он не вводит каталоги и не отображает текстовые файлы. – 18446744073709551615

+0

он вводит каталоги, а ОП ничего не говорит о текстовых файлах (или любых файлах, кроме каталогов). Я не буду исправлять проблемы с «каталогами с пробелами». –

4

Ниже одна из возможных реализаций:

# my_ls -- recursively list given directory's contents and subdirectories 
# $1=directory whose contents to list 
# $2=indentation when listing 
my_ls() { 
    # save current directory then cd to "$1" 
    pushd "$1" >/dev/null 
    # for each non-hidden (i.e. not starting with .) file/directory... 
    for file in * ; do 
    # print file/direcotry name if it really exists... 
    test -e "$file" && echo "$2$file" 
    # if directory, go down and list directory contents too 
    test -d "$file" && my_ls "$file" "$2 " 
    done 
    # restore directory 
    popd >/dev/null 
} 

# recursively list files in current 
# directory and subdirectories 
my_ls . 

В качестве вы можете подумать о том, как изменить abov e, чтобы печатать полные пути к файлам (а не только отступы файла/dirnames), возможно, избавиться от pushd/popd (и необходимости второго параметра $2).

Кстати, обратите внимание на использование test XYZ && command, который полностью эквивалентен if test XYZ ; then command ; fi (т.е. выполнять command, если test XYZ успешно). Также обратите внимание, что test XYZ эквивалентен [ XYZ ], то есть вышеуказанное также эквивалентно if [ XYZ ] ; then command ; fi. Также обратите внимание, что любая точка с запятой ; может быть заменена новой строкой, они эквивалентны.

Извлеките условие test -e "$file" && (оставляйте только echo) и посмотрите, что произойдет.

Удалите двойные кавычки около "$file" и посмотрите, что произойдет, когда каталог, содержимое которого вы указываете, содержит имена файлов с пробелами в них. Добавьте set -x в начало скрипта (или вместо него вместо этого введите sh -x scriptname.sh), чтобы включить отладочный вывод и посмотреть, что происходит в деталях (перенаправить вывод отладки в файл, запустите sh -x scriptname.sh 2>debugoutput.txt).

также список скрытых файлов (например .bashrc):

... 
for file in * .?* ; do 
    if [ "$file" != ".." ] ; then 
    test -e ... 
    test -d ... 
    fi 
done 
... 

Обратите внимание на использование != (сравнение строк) вместо -ne (числовое сравнение.)

Другой метод будет порождать подоболочки вместо использования pushd/popd:

my_ls() { 
    # everything in between roundbrackets runs in a separatly spawned sub-shell 
    (
    # change directory in sub-shell; does not affect parent shell's cwd 
    cd "$1" 
    for file in ... 
     ... 
    done 
) 
} 

Обратите внимание, что на некоторых реализациях оболочки существует жесткое ограничение (~ 4k) на количество символов, которые могут быть переданы как аргумент for (или любой встроенной или внешней команде.) Поскольку оболочка expands, inline, * to a list of all matching filenames до фактического выполнения на нем for, вы можете столкнуться с проблемой, если * раскрывается внутри каталога с большим количеством файлов (такая же проблема вы столкнетесь при запуске, скажем ls * в том же каталоге, e .г. получите ошибку, например Command too long.)

+0

вы можете использовать 'shopt -s dotglob' для отображения скрытых файлов. – ghostdog74

+0

@ghostdog - не переносится. '. *' (или '.? *', чтобы пропустить '.' с места в карьер) делает трюк просто прекрасным и переносимым тоже. – vladr

0

С технической точки зрения, ни find, ни ls не используются find2perl | perl или File::Find напрямую.

 
$ find2perl -type d | perl 
$ perl -MFile::Find -e'find(sub{-d&&print"$File::Find::name\n"},".")' 
+0

, но тогда, если это так, используя Python/Ruby/PHP и т. Д. Любой язык, который может отображать файлы, технически не будет использовать 'ls' или' find' – ghostdog74

+0

@ ghostdog74 Очевидно. Но поскольку все серьезные ответы получили меньше, чем потрясающие отзывы, это что-то ... менее серьезное. (Я на самом деле собирался написать клоун 'find' в C и скрипт оболочки, который компилирует + запускает его, но решил, что это слишком много усилий для шутки.) – ephemient

3

Поскольку для Баша, это удивительно, что это не было уже сказано:
(globstar действует с Баша 4.0+)

shopt -s globstar nullglob dotglob 
echo **/*/ 

Это все.
Конечная косая черта / есть, чтобы выбрать только dirs.

Опция globstar активирует ** (поиск рекурсивно). Вариант nullglob удаляет *, когда он не соответствует файлу/директории. Опция dotglob содержит файлы, начинающиеся с точки (скрытые файлы).

Смежные вопросы