Список всех подкаталогов в linux

Есть ли простой способ перечислять только каталоги в данном каталоге в Linux? Чтобы лучше объяснить, я могу сделать:

find mydir -type d

который дает:

mydir/src
mydir/src/main
mydir/bin
mydir/bin/classes

Вместо этого я хочу:

mydir/src/main
mydir/bin/classes

Я могу сделать это в bash script, который перебирает строки и удаляет предыдущую строку, если следующая строка содержит путь, но мне интересно, есть ли более простой метод, который не использует bash loop.

Ответ 1

find . -type d | sort | awk '$0 !~ last "/" {print last} {last=$0} END {print last}'

Ответ 2

Если вы хотите только листовые каталоги (каталоги, которые не содержат какой-либо подкаталога), посмотрите этот другой вопрос. Ответ также объясняет это, но вкратце:

find . -type d -links 2

Ответ 3

Я не могу думать ни о чем, что сделает это без цикла. Итак, вот несколько циклов:

Отображает каталоги листьев в текущем каталоге независимо от их глубины:

for dir in $(find -depth -type d); do [[ ! $prev =~ $dir ]] && echo "$dir" ; prev="$dir"; done

Эта версия правильно обрабатывает имена каталогов, содержащие пробелы:

saveIFS=$IFS; IFS=$'\n'; for dir in $(find -depth -type d ); do [[ ! $prev =~ $dir ]] && echo "${dir}" ; prev="$dir"; done; IFS=$saveIFS

Вот версия, использующая предложение Jefromi:

find -depth -type d | while read dir;  do [[ ! $prev =~ $dir ]] && echo "${dir}" ; prev="$dir"; done

Ответ 4

Если вы ищете что-то визуальное, tree -d приятно.

drinks
|-- coke
|   |-- cherry
|   `-- diet
|       |-- caffeine-free
|       `-- cherry
|-- juice
|   `-- orange
|       `-- homestyle
|           `-- quart
`-- pepsi
    |-- clear
    `-- diet

Ответ 5

Это все еще цикл, так как он использует команду ветвления в sed:

find -depth -type d |sed 'h; :b; $b; N; /^\(.*\)\/.*\n\1$/ { g; bb }; $ {x; b}; P; D'

Основываясь на script в info sed (uniq work-alike).

Изменить. Здесь вызывается sed script с комментариями (скопировано из info sed и изменено):

# copy the pattern space to the hold space
h 

# label for branch (goto) command
:b
# on the last line ($) goto the end of 
# the script (b with no label), print and exit
$b
# append the next line to the pattern space (it now contains line1\nline2
N
# if the pattern space matches line1 with the last slash and whatever comes after
# it followed by a newline followed by a copy of the part before the last slash
# in other words line2 is different from line one with the last dir removed
# see below for the regex
/^\(.*\)\/.*\n\1$/ {
    # Undo the effect of
    # the n command by copying the hold space back to the pattern space
    g
    # branch to label b (so now line2 is playing the role of line1
    bb
}
# If the `N' command had added the last line, print and exit
# (if this is the last line then swap the hold space and pattern space
# and goto the end (b without a label) 
$ { x; b }

# The lines are different; print the first and go
# back working on the second.
# print up to the first newline of the pattern space
P
# delete up to the first newline in the pattern space, the remainder, if any,
# will become line1, go to the top of the loop
D

Вот что делает регулярное выражение:

  • / - запустите шаблон
  • ^ - соответствует началу строки
  • \( - запустить группу захвата (подвыражение обратной ссылки)
  • .* - ноль или более (*) любого символа (.)
  • \) - группа конечного захвата
  • \/ - косая черта (/) (экранированная с \)
  • .* - ноль или более любого символа
  • \n - новая строка
  • \1 - копия обратной ссылки (которая в этом случае является тем, что было между началом строки и последней косой чертой)
  • $ - соответствует концу строки
  • / - завершить шаблон

Ответ 6

Я думаю, вы можете посмотреть все каталоги, а затем перенаправить вывод и использовать xargs для подсчета числовых файлов для каждого подкаталога, когда нет подкаталога (xargs find SUBDIR -type d | wc -l... что-то вроде этого, я не могу проверить прямо сейчас), вы нашли лист.

Это все еще цикл.

Ответ 7

Попробуйте использовать один однострочный (протестированный в Linux и OS X):

find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' \;