Exibe todas as pastas que não possuem subdiretório [duplicado]

3

Como exibo todas as pastas que não possuem subdiretório usando o terminal?

    
por Jaimin 13.06.2016 / 09:54

2 respostas

2

Tente isto:

find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a)print d}' RS='
$ mkdir -p a/b/c/x1 a/b/c/x2 a/b/x3 a/x4
$ find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a)print d}' RS='
find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a) {sub(/^.*[/]/,"",d); print d}}' RS='
$ find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a) {sub(/^.*[/]/,"",d); print d}}' RS='
find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a)print d}' RS='
$ mkdir -p a/b/c/x1 a/b/c/x2 a/b/x3 a/x4
$ find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a)print d}' RS='
find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a) {sub(/^.*[/]/,"",d); print d}}' RS='
$ find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a) {sub(/^.*[/]/,"",d); print d}}' RS='%pre%'
x5
x4
x3
x1
x2
'
' ./a/x4 ./a/b/x3 ./a/b/c/x1 ./a/b/c/x2
'
' x5 x4 x3 x1 x2
'
' ./a/x4 ./a/b/x3 ./a/b/c/x1 ./a/b/c/x2
'

Como funciona

Para garantir a segurança de todos os nomes de diretório possíveis, usamos listas separadas por nul para cada etapa do pipeline.

  • find . -type d -print0

    Isso obtém uma lista de todos os subdiretórios do diretório atual.

  • sort -z

    Isso classifica os diretórios como o efeito de colocar subdiretórios após seus diretórios pai.

  • gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a)print d}' RS='a[$0]'

    Isso coloca a lista de diretórios em um array associativo. Para cada diretório adicionado, ele verifica se o pai dos diretórios está na matriz. Se for, elimina-o da matriz. Vamos ver este passo de cada vez:

    • a

      Isso adiciona o diretório nomeado no registro atual como uma chave na matriz sub(/[/][^/]*$/, "") . (Não atribuímos um valor a isso porque não precisamos de um valor.)

    • $0

      Isso remove o último subdiretório de $0 , de modo que if ($0 in a) delete a[$0] agora se refere ao diretório pai.

    • a

      Se o diretório pai for uma chave em END{for (d in a) print d} , então o excluiremos.

    • RS='%code%'

      Isso imprime cada diretório para o qual não encontramos subdiretórios. (Devido ao modo como os arrays do awk funcionam, a saída não está em nenhuma ordem específica.)

    • %code%

      Isto diz ao awk para esperar uma entrada separada. Em outras palavras, na entrada, o awk usa o caractere nul como o separador de registro.

Exemplo

Vamos criar alguns diretórios e verificar se a saída lista apenas os diretórios que não têm subdiretórios:

%pre%

Variação: imprimindo apenas o nome da base do diretório

%pre%

Para ilustrar, vamos executar isso nos mesmos diretórios acima:

%pre%     
por John1024 13.06.2016 / 10:22
2

Você pode encontrar um "encontrar-dentro-de-encontrar", por exemplo

find . -type d -exec bash -c '
  [[ -z $(find "$1" -mindepth 1 -type d -print -quit) ]] && printf "%s\n" "$1"      
' bash {} \;

Se você não quiser os componentes principais do caminho,

find . -type d -exec bash -c '
  [[ -z $(find "$1" -mindepth 1 -type d -print -quit) ]] && printf "%s\n" "${1##*/}"
' bash {} \;

Eu não posso deixar de sentir que deveria haver uma maneira "inteligente" de fazer isso usando -depth

    
por steeldriver 13.06.2016 / 14:30