Por que a localização com -delete apagou os arquivos no meu diretório / save / quando a localização sem exclusão não conseguiu localizá-los?

20

Eu quero excluir todos os arquivos na árvore de diretórios atual, exceto aqueles em save. Eu executei este comando:

 find . \( -name save -prune \) -o -type f -ls | grep /save/

e não encontrou nenhum. Mas quando eu executei este comando:

 find . \( -name save -prune \) -o -type f -delete

Todos esses arquivos em / save / foram embora. o que estou perdendo?

Otheus
fonte
4
Ai ... eu aprendi alguma coisa hoje (graças a você). E eu recomendo um simples mv save/ ../some/safer/locationantes de um comando de exclusão "genérico" (... mas é claro, antes de sua postagem, eu teria feito a mesma verificação e enfrentado o mesmo problema!). Agora vá encontrar um bom "undelete" para o sistema de arquivos em que os arquivos estavam ^ ^ #
Olivier Dulac
3
Minha dor é sua prevenção.
Otheus
11
1000 graças a você. Código (? Frequentemente) trabalha em maneiras misteriosas ...
Olivier Dulac
@lesmana Eu votei sua resposta lá. infelizmente, minha versão do find não me dá um aviso tão bom :(
Otheus

Respostas:

26

-deleteimplica -depthque não funciona -prune( -depthcomeça com as folhas). Há um aviso sobre isso no manual da versão GNU ( -deleteé uma extensão do FreeBSD agora também suportada pelo GNU finde algumas outras implementações).

info find --index-search=-delete

O uso da ação '-delete' na linha de comando ativa automaticamente a opção '-path' (* note find Expressions: :). Isso pode ser surpreendente se você estava testando anteriormente com '-print', por isso é melhor lembrar de usar '-pth' explicitamente.

info find --index-search=-prune

Como '-delete' implica '-pth', usar '-prune' em combinação com '-delete' pode resultar na exclusão de mais arquivos do que você pretendia.

Aqui, você tem a opção de usar rm:

find . -name save -prune -o -type f -exec rm -f {} +

(potencialmente inseguro se houver diretório gravável por outras pessoas, pois é possível excluir arquivos fora da árvore de diretórios atual, substituindo os diretórios por links simbólicos enquanto você executa esse comando).

Uma alternativa mais segura:

find . -name save -prune -o -type f -execdir rm -f -- {} \;

Isso não tem o problema mencionado acima, mas significa executar um rmpor arquivo. A --é necessária para a implementação FreeBSD, e não o GNU um que nomes de arquivos prefixos com ./.

Como alternativa, conforme sugerido por Costas:

LC_ALL=C find . ! -name save ! -path '*/save/*' -type f -delete

(mas isso ainda é desnecessário em savediretórios)

The LC_ALL=Cis there *corresponde a qualquer sequência de bytes (mesmo aqueles que não formam caracteres válidos no código de idioma atual). Observe que isso afetará o idioma das mensagens de erro (inglês em vez do idioma do usuário).

Stéphane Chazelas
fonte
Qual é o problema de segurança aqui rm?
jrw32982 suporta Monica
@ jrw32982, veja edit com link para o GNU find manual
Stéphane Chazelas