encontre todos os subdiretórios finais em uma árvore

11

dada a seguinte estrutura:

oz123@debian:~/ $ tree .
.
├── a
│   ├── a1
│   ├── a2
│   └── a3
├── a1
│   ├── a11
│   ├── a12
│   └── a31
├── b
│   └── b1
│       ├── b11
│       │   └── b21
│       │       └── b31
│       ├── b12
│       └── b3
└── c

16 directories, 0 files

Como encontro todos os nós finais?

Encontrei as seguintes soluções que parecem boas, mas tenho que provar que não há um caso de teste que irá falhar.

A página de ajuda dos -linksestados:

Você também pode procurar arquivos que tenham um certo número de links, com '-links'. Os diretórios normalmente têm pelo menos dois links físicos; deles . entrada é a segunda. Se eles tiverem subdiretórios, cada um deles também terá um link físico chamado .. para seu diretório pai. O . e .. as entradas do diretório normalmente não são pesquisadas, a menos que sejam mencionadas na linha de comando find.

solução possível:

oz123@debian:~/ $ find .  -type d  -links 2
./a/a2
./a/a3
./a/a1
./c
./a1/a31
./a1/a11
./a1/a12
./b/b1/b12
./b/b1/b3
./b/b1/b11/b21/b31
  • Alguém pode fornecer uma solução melhor (sem usar canos e sed, isso tem desempenho ...)
  • Funcionará em qualquer sistema de arquivos?
Oz123
fonte
3
Você não encontrará mais desempenho do que o -links 2truque. Não vai funcionar btrfs.
Stéphane Chazelas

Respostas:

3

Como complemento à sua própria solução -links, quero apenas acrescentar que ela não funcionará em sistemas de arquivos que não seguem a convenção de link de diretório do Unix. Na man findopção on, -noleafsão pelo menos CD-ROM, sistemas de arquivos MS-DOS e pontos de montagem de volume do AFS.

Para uma referência, essa questão já foi discutida com diferentes soluções que são realmente mais lentas e geralmente recorrem à tubulação para sed / awk e similares.

Miroslav Koškár
fonte
3

Existe uma opção um pouco mais óbvia -empty:

find . -type d -empty

upd. Ok, você está certo dessa maneira não funcionará com arquivos em diretórios.

Portanto, aqui está uma versão independente do sistema de arquivos fixo:

find dtest/ -type d -exec sh -c "if [ \$(find {} -maxdepth 1 -type d | wc -l) -eq 1 ]; then echo {} ; fi" \;
pressa
fonte
2
Se eu entendi a pergunta, os diretórios finais podem conter arquivos. Isso não iria imprimir os diretórios como eles não seria "esvaziar" ...
Stefan
@rush, subdirs pode estar vazio ou não
Oz123
@ Oz123, verifique minha atualização, ela deve ser rápida o suficiente, mas um pouco mais lenta em comparação com o seu caminho.
apressar
@ Rush, obrigado, mas eu realmente preciso evitar os canos, eles podem tornar as coisas mais lentas.
Oz123
1

find . -type d -links 2funciona na maioria dos sistemas de arquivos, mas não em todos. Eu acho que não há uma maneira de saber além de saber quais tipos de sistema de arquivos têm a propriedade de que os diretórios contêm um link para si mesmos. O GNU find detecta isso dinamicamente (se ele imprimir algo sobre “Ativando automaticamente a opção find -noleaf”, você sabe que seu sistema de arquivos não possui essa propriedade). Os tipos mais comuns de sistema de arquivos estão ok, mas não o FAT ou o btrfs.

Se você quiser ter certeza, precisará testar cada diretório. Uma maneira de fazer isso é chamar findnovamente para cada subdiretório.

find . -type d ! -exec sh -c '
   find "$1/." ! -name . -type d -prune | grep -q "^"' sh {} \; -print

(com o GNU find, você pode substituir -prunepor -print -quitpara torná-lo um pouco mais eficiente).

Outra maneira é pós-processar a saída de find. Com find -depth, um diretório folha é aquele que não segue um subdiretório próprio.

find . -depth -type d -print0 |
awk -v RS='\0' '
    substr(previous, 1, length($0) + 1) != $0 "/"
    { previous = $0 }
'
Gilles 'SO- parar de ser mau'
fonte
0

Experimente a seguinte solução (deve ser compatível com Linux, Unix e OS X):

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

É uma abordagem semelhante à solução urgente , mas sem tubos.

kenorb
fonte