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:
-
-pruneimpede que a localização desça para um diretório. Em outras palavras,-pruneignora o conteúdo do diretório. No seu caso,-name b -pruneevita que o encontro descesse em qualquer diretório com o nomeb. -
-depthfaz 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-depthem vigor. -
-deleteimplica-depth, portanto, ele pode excluir os arquivos primeiro e depois o diretório vazio.-deletese recusa a excluir diretórios não vazios. Eu acho que seria possível adicionar uma opção para forçar-deletea excluir diretórios não vazios e / ou evitar que-deleteindicasse-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