Exclua arquivos e diretórios por seus nomes. Não existe tal arquivo ou diretório

32

Preciso excluir todos os dados compilados:

  • diretórios chamados build,
  • diretórios chamados obj,
  • arquivos * .so.

Eu escrevi um comando

find \( -name build -o -name obj -o -name *.so \) -exec rm -rf {} \;

que percorre todos os diretórios recursivamente e exclui tudo o que preciso.

Por que eu tenho essa saída no final? Talvez eu deva escrever um comando diferente.

find: `./3/obj': No such file or directory
find: `./3/build': No such file or directory
find: `./1/obj': No such file or directory
find: `./1/build': No such file or directory
find: `./2/obj': No such file or directory
find: `./2/build': No such file or directory
Maksim Dmitriev
fonte
em qual sistema você é? você deve sempre usar findcomo esta find /search_directory optionsomiting o diretório de pesquisa não é uma boa idéia
kiwy
A exclusão automatizada como essa é uma má ideia. Você pode fazer com que um script forneça candidatos, que você deve examinar para garantir que não está excluindo nada de importante ou necessário para o sistema. Você não está explícito onde está executando isso. Se você estiver fazendo isso apenas em um espaço de usuário, suponho que não possa causar muito dano, mas verifique se não está fazendo isso acidentalmente em uma área do sistema. Você definitivamente deseja executar um script como usuário.
Faheem Mitha
@ Kiwy, @ FaheemMitha, o comando será usado apenas no directoty do projeto; não fará nenhum mal lá.
Maksim Dmitriev
Related: stackoverflow.com/questions/22462124/…
Ciro Santilli adicionou uma nova foto

Respostas:

54

Use -pruneos diretórios que você deseja excluir de qualquer maneira para dizer findpara não se preocupar em tentar encontrar arquivos neles:

find . \( -name build -o -name obj -o -name '*.so' \) -prune -exec rm -rf {} +

Observe também que *.soprecisa ser citado, caso contrário, ele pode ser expandido pelo shell para a lista de .soarquivos no diretório atual.

O equivalente ao seu GNU- -regextype seria:

find . \( -name build -o -name obj -o -name '*?.so' \) -prune -exec rm -rf {} +

Observe que se você usar a sintaxe específica do GNU, poderá usar em -deletevez de -exec rm -rf {} +. Com -delete, o GNU findliga -depthautomaticamente. Ele não executa comandos externos, dessa forma, é mais eficiente e também mais seguro, pois remove a condição de corrida em que alguém pode fazer com que você remova os arquivos errados, alterando um diretório para um link simbólico entre as horas findlocaliza um arquivo e o rmremove (consulte info -f find -n 'Security Considerations for find'para obter detalhes).

find . -regextype posix-egrep -regex '.*/((obj|build)(/.*)?|.+\.so)' -delete
Stéphane Chazelas
fonte
-deletetambém lida com coisas como espaços melhor
Izkata
@ Izkata, não é melhor do que o -exec rm -rf {} +que também não tem problema.
Stéphane Chazelas
@StephaneChazelas - Estou confuso {}- devem ser citados ou não? Parece funcionar sem aspas, mas o GNU Findutils Manual usa '{}'no exemplo. Você poderia por favor esclarecer?
grebneke
1
@ Gregbneke, acho que há um post em algum lugar em que citações de reivindicações podem ser necessárias em versões muito antigas csh, mas nunca pude verificar essa reivindicação. Eles não são necessários em nenhum shell moderno que eu conheça. Definitivamente, eles não são exigidos pelo POSIX. Os exemplos POSIX não os usam.
Stéphane Chazelas
3
E -deletenão pode ser usado com diretórios.
St0rM
8

Acho que o motivo é que ele findexclui a árvore de diretórios primeiro e tenta verificar o conteúdo do diretório, o que obviamente não é a melhor ordem possível. Você pode forçar finda verificar o conteúdo primeiro:

find . -depth ...

Você deve considerar o uso -deletede arquivos e -exec rmdirdiretórios.

Hauke ​​Laging
fonte
0

Minha solução

find . -regextype posix-egrep -regex ".*/(obj|build|.+\.so)" -prune -exec rm -rf {} +

+ vs \; no comando -exec

Maksim Dmitriev
fonte
Isso nem sempre funciona, apenas se nenhum limite entre execuções ocorrer dentro de um diretório excluído.
Gilles 'SO- stop be evil'
@Gilles, o que significa "fronteira entre execuções"?
Maksim Dmitriev
1
-exec … {} +executa o comando para vários arquivos de cada vez, quantos cabem na linha de comando. Se houver muitos arquivos (ou mais precisamente, se o comprimento total dos caminhos for muito longo), findserá executada várias instâncias de rm, e, portanto, poderá acabar removendo um diretório que ele está percorrendo. É apenas menos provável com o +que com ;, mas +não resolve o problema.
Gilles 'SO- stop be evil'