find . -type d
normalmente irá mostrar
./dir1
./dir1/dir2
./dir3
./dir3/dir4
./dir3/dir4/dir5
...
Eu só quero o
./dir1/dir2
./dir3/dir4/dir5
, sem seu pai ./dir1, ...
Em outras palavras, quero apenas ver diretórios que não contenham subdiretórios.
Qualquer ideia?
EDIT: descobri que -links 2
funciona em um ambiente Linux normal, por exemplo,
docker run -it --rm ubuntu:bionic find /etc -type d -links 2
funciona perfeitamente.
Porém, quando eu monto um diretório (do MacOS ou Windows) no contêiner do docker, as coisas mudam, não funciona, você pode tentar isto:
docker run -it --rm -v /etc:/etc_of_host ubuntu:bionic find /etc_of_host -type d -links 2
Responder1
Com zsh
:
has_subdirs() () (( $# )) ${1-$REPLY}/*(ND/Y1)
print -rC1 -- **/*(ND/^+has_subdirs)
Ou diretamente sem a função intermediária:
print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
Isso é:
fn() some-command
define umafn
funçãosome-command
como o corpo, como no Bourne-shell e na maioria dos shells do tipo Bourne.() { code } args
uma função anônima que é executadacode
comoargs
parâmetro posicional.(( $# ))
aqui o corpo dessa função anônima é uma expressão aritmética que resolve paraverdadeiroif$#
(o número de argumentos) for diferente de zero.${param-default}
(do shell Bourne) se expande para$param
se o parâmetro estiver definido oudefault
não. Aqui com${1-$REPLY}
, permitimos que nossa função seja chamada diretamente (comohas_subdirs mydir
) ou como uma função qualificadora globbing como abaixo.$dir/*(ND/Y1)
expande para os arquivos do tipo diretório em$dir
(/
) incluindo os ocultos (D
otglob) e não gera erros se não houver correspondência (N
ullglob). Mas comY1
, paramos na primeira partida. Portanto, a função anônima (e, portantohas_subdirs
, ) retornará true se o diretório contiver pelo menos um subdiretório.print -rC1
imprime seus argumentosr
aw no1
C
olumn^+has_subdirs
restringe a arquivos para os quais ahas_subdirs
função ( ) não^
retorna verdadeiro.
Se você tiver que usar o bash
shell, basta fazer:
zsh << 'EOF'
print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF
Ou para armazenar o resultado em um array bash (precisa do bash-4.4+):
readarray -td '' array < <(zsh << 'EOF'
print -rNC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF
)
(usando registros delimitados por NUL para poder armazenar caminhos arbitrários).
Se você não tem zsh
, mas tem perl
, você poderia fazer:
find . -depth -type d -print0 |
perl -l -0ne 'print if rindex $prev, "$_/", 0; $prev = $_'
Ou se você tiver GNU awk
:
find . -depth -type d -print0 |
gawk -v 'RS=\0' 'index(prev, $0"/") != 1; {prev = $0}'
Aqueles find
imprimiram os diretóriosprofundidade primeiro(sai antes dos galhos em que estão) e obtém perl
/ awk
para imprimir os registros que não foram encontrados seguidos de /
no início do registro anterior.
Novamente, para armazenar os arquivos em um array bash 4.4+, você deseja mudar para registros delimitados por NUL na saída movendo o -l
after -0
in perl
ou add -v 'ORS=\0'
in gawk
:
readarray -td array < <(
find . -depth -type d -print0 |
perl -0lne 'print if rindex $prev, "$_/", 0; $prev = $_'
)
readarray -td array < <(
find . -depth -type d -print0 |
gawk -v 'RS=\0' -v 'ORS=\0' 'index(prev, $0"/") != 1; {prev = $0}'
)
Em alguns sistemas e sistemas de arquivos (como ext4
sistemas de arquivos em sistemas baseados em Linux), você pode confiar no fato de que os diretórios que possuem subdiretórios têm uma contagem de links maior que 2 ( dir
e dir/.
um link adicional para cada dir/subdir/..
).
print -rC1 -- **/*(ND/l-3)
Ou usando find
em qualquer shell:
find . -type d -links -3
Isso não funcionará btrfs
(que foi substituído ext4
como sistema de arquivos padrão em várias distribuições Linux), por exemplo, onde a contagem de links de diretórios é sempre uma, então eu não recomendaria isso como uma solução geral.
O mesmo para sistemas de arquivos union, como é o seu caso, como overlayfs
onde encontro algunsmescladoos diretórios têm uma contagem de links igual a 1, independentemente de conterem subdiretórios ou não.
No entanto, onde quer que seja utilizável, tem a vantagem sobre as soluções que contam manualmente os subdiretórios de que você não precisa de acesso de leitura ao diretório (apenas acesso de pesquisa ao seu pai).
Responder2
O que você procura é:
find . -type d -links 2
Cada diretório no sistema de arquivos possui pelo menos dois links físicos - o próprio diretório no pai e '.' entrada. Cada entrada '..' nos subdiretórios adiciona um novo link físico ao diretório. Então você só precisa encontrar diretórios com dois links físicos.
O comando sugerido em outra resposta
find . -type d -links -3
Faz o mesmo, mas com a declaração "diretórios com menos de três links físicos para ele".
Responder3
O mais sortido:
p="";(find . -type d;echo) | while read d; do [[ $p && $d != $p/* ]] && echo $p; p=$d; done
Em uma linha
a="";(find . -type d;echo )|while read i; do if [[ (! $i =~ $a) && ("$a" != "") ]]; then echo $a; fi; a=$i;done
Como a operação mencionou:
a="";(find . -type d;echo )|while read i; do [[ $i != $a/* && ! -z "$a" ]] && echo $a; a=$i;done
Responder4
Ler man find
. A -mindepth
opção é o que você deseja.