TL; DR: a melhor maneira é usar -exec rm
em vez de -delete
.
find a \( -name b -prune \) -o -type f -exec rm {} +
Explicação:
Por que encontrar reclamações quando você tenta usar -delete
com -prune
?
Resposta curta: porque -delete
implica em -depth
e -depth
torna -prune
ineficaz.
Antes de chegarmos à resposta longa, primeiro observe o comportamento de encontrar com e sem -depth
:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
Não há garantia sobre o pedido em um único diretório. Mas há uma garantia de que um diretório é processado antes de seu conteúdo. Anote foo/
antes de qualquer foo/*
e foo/bar
antes de qualquer foo/bar/*
.
Isso pode ser revertido com -depth
.
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
Observe que agora todos os foo/*
aparecem antes de foo/
. Mesmo com foo/bar
.
Resposta mais longa:
-
-prune
impede que a localização desça para um diretório. Em outras palavras,-prune
ignora o conteúdo do diretório. No seu caso,-name b -prune
evita que o encontro descesse em qualquer diretório com o nomeb
. -
-depth
faz find para processar o conteúdo de um diretório antes do próprio diretório. Isso significa que, no momento em que find, é possível processar a entrada de diretóriob
, seu conteúdo já foi processado. Assim,-prune
é ineficaz com-depth
em vigor. -
-delete
implica-depth
, portanto, ele pode excluir os arquivos primeiro e depois o diretório vazio.-delete
se recusa a excluir diretórios não vazios. Eu acho que seria possível adicionar uma opção para forçar-delete
a excluir diretórios não vazios e / ou evitar que-delete
indicasse-depth
. Mas isso é outra história.
Existe outra maneira de conseguir o que você deseja:
find a -not -path "*/b*" -type f -delete
Isso pode ou não ser mais fácil de lembrar.
Este comando ainda desce para o diretório b
e processa cada arquivo nele apenas para -not
rejeitá-los. Isso pode ser um problema de desempenho se o diretório b
for enorme.
-path
funciona de forma diferente de -name
. -name
corresponde apenas ao nome (do arquivo ou diretório) enquanto -path
está correspondendo no caminho inteiro. Por exemplo, observe o caminho /home/lesmana/foo/bar
. -name -bar
corresponderá porque o nome é bar
. -path "*/foo*"
corresponderá porque a string /foo
está no caminho. -path
tem algumas complexidades que você deve entender antes de usá-lo. Leia a página do manual de find
para mais detalhes.
Tenha em atenção que isto não é 100% infalível. Há chances de "falsos positivos". A maneira como o comando é escrito acima, ignorará qualquer arquivo que tenha qualquer diretório pai cujo nome esteja iniciando com b
(positivo). Mas também irá ignorar qualquer arquivo cujo nome esteja iniciando com b
, independentemente da posição na árvore (falso positivo). Isso pode ser corrigido escrevendo uma expressão melhor que "*/b*"
. Isso é deixado como um exercício para o leitor.
Suponho que você usou a
e b
como espaços reservados e os nomes reais são mais como allosaurus
e brachiosaurus
. Se você colocar brachiosaurus
no lugar de b
, a quantidade de falsos positivos será drasticamente reduzida.
Pelo menos os falsos positivos serão não excluídos, por isso não será tão trágico. Além disso, você pode verificar os falsos positivos primeiro executando o comando sem -delete
(mas lembre-se de colocar o -depth
implícito) e examinar a saída.
find a -not -path "*/b*" -type f -depth