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 queif ($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%