2009-10-15 2 views
13

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

find mydir -type d 

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

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

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

mydir/src/main 
mydir/bin/classes 

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

+0

С вашим примером, 'найти Mydir -mindepth 2 - тип d' будет работать, но он не будет, когда у вас будет несколько максимальных глубин. Вы действительно хотите перечислять только каталоги, которые не содержат других каталогов, или вы хотите увидеть определенный уровень структуры каталогов? – Cascabel

+0

Да, спасибо за разъяснение - мой пример был упрощенным примером. Я действительно искал более общее решение. Кроме того, я ищу, чтобы увидеть общую структуру каталогов, на самом деле не заботятся о файлах в каталогах (так же, в этом контексте листовое означает «каталог листьев»). Благодарю. – amol

ответ

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

Спасибо, просто вид решения, который я искал :) – amol

+0

Это приведет к получению правильных, но несортированных результатов без 'sort' (чтобы вы могли поместить его в конец, вместо этого, если хотите). –

+0

Это не работает, если у вас есть два каталога: foo/bar и foo/bar_baz. foo/bar не будет напечатано. – mattismyname

4

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

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

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 
+0

ОП спрашивал, существует ли более простой способ, чем цикл по выходному сигналу, а не как написать цикл. Тем не менее, также неплохо использовать 'find .... | в то время как читать dir' вместо 'for dir в $ (...)', потому что он не должен делать всю находку перед печатью чего-либо. – Cascabel

+0

@Jefromi: Piping 'find' в' while' также корректно обрабатывает имена с пробелами. –

+0

Ну, избегая циклов, очевидно, не является жестким «требованием», но я надеялся, что будет проще + интуитивно понятный способ сделать это без циклов. Спасибо, что нашли | хотя информация хотя. – amol

0

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

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

на основе сценария в info sed (уник работа Двойник).

Редактировать Вот sed сценарий вырвались с комментариями (скопированные из 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 - копия обратная ссылка (которая в этом случае находится между началом и последней косой чертой)
  • $ - соответствует концу строки
  • / - конец шаблона
+0

Ваше предложение работает просто отлично, но мне трудно понять. Спасибо, хотя я попытаюсь понять, что означают опции sed. – amol

0

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

Это все еще петля.

+0

А .. Может быть, я не объяснил, что означает «лист». Это означает, что «лист-дир», так что если бы все файлы были файлы, это все равно было бы «листом» для моей проблемы. – amol

+0

ouhla, i ' m устал, я ищу каталоги под и wc -l == 0, это должно трюк ... – LB40

4

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

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

Спасибо, это полезно также (не для моей текущей проблемы, но полезно знать) Мне интересно, это дерево недавнее дополнение? Я помню, что мне нужно было что-то вроде этого (было на RHEL в то время, теперь на Ubuntu) примерно год назад, и вместо этого использовал сценарий по адресу http://centerkey.com/tree. – amol

10

Если вы хотите только листовые каталоги (каталоги, которые не содержат какой-либо подкаталог), посмотрите на this other question. Ответ также explains it, но вкратце это:

find . -type d -links 2 
+1

На Mac, по крайней мере, ссылки включают текущие, родительские и вспомогательные каталоги, а также файлы. Таким образом, это решение работает только для пустых каталогов листов. –

+0

Я просто заметил, что он тоже не работает на креплениях SMB. Но это делается на монтировании NFS. Но в ситуациях, когда он работает (локальные или NFS-каталоги Linux), это, безусловно, самое простое решение. – mivk

0

Попробуйте следующее Однострочника (протестировано на Linux & OS X):

find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' \; 
Смежные вопросы