Как рекурсивно перечислить подкаталоги в Bash без использования, “находят” или команды “ls”?

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

11
задан Benjamin W. 18 September 2018 в 17:43
поделиться

7 ответов

Вы можете сделать это только с Shell

#!/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

или если у вас есть Bash 4.0

#!/bin/bash
shopt -s globstar
for file in /path/**
do
    echo $file
done
30
ответ дан 3 December 2019 в 00:56
поделиться
$ 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
0
ответ дан 3 December 2019 в 00:56
поделиться

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

tree -d
11
ответ дан 3 December 2019 в 00:56
поделиться

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

Тест или [] команда / встроенный вариант для проверки, если файл является каталогом.

Применить рекурсию, и вы закончите.

1
ответ дан 3 December 2019 в 00:56
поделиться

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

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

1
ответ дан 3 December 2019 в 00:56
поделиться

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

$ find2perl -type d | perl
$ perl -MFile::Find -e'find(sub{-d&&print"$File::Find::name\n"},".")'
0
ответ дан 3 December 2019 в 00:56
поделиться

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

# 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 .

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

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

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

Удалите двойные кавычки вокруг "$ file" и посмотрите, что произойдет, когда каталог, содержимое которого вы перечисляете, будет содержать имена файлов с пробелами. Добавьте set -x в верхней части скрипта (или вызовите его как sh -x scriptname.sh ), чтобы включить вывод отладки и посмотреть, что происходит в деталях (для перенаправления отладки вывод в файл, запустите sh -x имя_сценария.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) на количество символов, которое может быть передано в качестве аргумента для (или любой встроенной или внешней команде, если на то пошло). Поскольку оболочка расширяется, встроенная, * в список всех совпадающих имен файлов перед фактическим выполнением для на нем, вы можете столкнуться с проблемой, если * развернуть внутри каталога с большим количеством файлов (такая же проблема у вас) Я столкнусь при запуске, скажем, ls * в том же каталоге, например, получите ошибку вроде Command too long .)

5
ответ дан 3 December 2019 в 00:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: