Desejo excluir recursivamente todos os arquivos que não foram acessados por um tempo na pasta a
, exceto todos os arquivos na subpasta b
.
find a \( -name b -prune \) -o -type f -delete
No entanto, recebo uma mensagem de erro:
find: A ação -delete ativa automaticamente a profundidade, mas -prune não faz nada quando a profundidade está em vigor. Se você quiser continuar de qualquer maneira, use explicitamente a opção -thpth.
A adição -depth
faz com que todos os arquivos b
sejam incluídos, o que não deve acontecer.
Alguém conhece uma maneira segura de fazer isso funcionar?
a
menosa/b
?cd a && ls -d !(b/*)
funcionar? (Para fazê-lo, apenasrm -r
em vez dels -d
.)a
(exceto arquivos ema/b
).-r
para a rm. Parece que o que você está perguntando é facilmente respondido usando o globbing estendido do bash, e então o que você faz com o resultado do globbing é com você.Respostas:
TL; DR: a melhor maneira é usar em
-exec rm
vez de-delete
.Explicação:
Por que encontrar reclamar quando você tentar usar
-delete
com-prune
?Resposta curta: porque
-delete
implica-depth
e-depth
torna-prune
ineficaz.Antes de chegarmos à resposta longa, observe primeiro o comportamento de encontrar com e sem
-depth
:Não há garantia sobre o pedido em um único diretório. Mas há uma garantia de que um diretório seja processado antes de seu conteúdo. Anote
foo/
antes de qualquerfoo/*
efoo/bar
antes de qualquerfoo/bar/*
.Isso pode ser revertido com
-depth
.Observe que agora todos
foo/*
aparecem antesfoo/
. O mesmo comfoo/bar
.Resposta mais longa:
-prune
impede que a localização desça para um diretório. Em outras palavras,-prune
pula o conteúdo do diretório. No seu caso,-name b -prune
impede que a localização desça para qualquer diretório com o nomeb
.-depth
faz encontrar para processar o conteúdo de um diretório antes do próprio diretório. Isso significa que no momento em que a find processa a entrada do diretório,b
seu conteúdo já foi processado. Assim-prune
é ineficaz com-depth
efeito.-delete
implica-depth
que ele possa 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 exclusão de diretórios não vazios e / ou impedir-delete
a implicação-depth
. Mas isso é outra história.Há outra maneira de conseguir o que você deseja:
Isso pode ou não ser mais fácil de lembrar.
Este comando ainda desce para o diretório
b
e processa todos os arquivos nele apenas para-not
rejeitá-los. Isso pode ser um problema de desempenho se o diretóriob
for enorme.-path
funciona de forma diferente do que-name
.-name
corresponde apenas ao nome (do arquivo ou diretório) enquanto-path
corresponde ao caminho inteiro. Por exemplo, observe o caminho/home/lesmana/foo/bar
.-name -bar
corresponderá porque o nome ébar
.-path "*/foo*"
corresponderá porque a cadeia/foo
está no caminho.-path
tem alguns meandros que você deve entender antes de usá-lo. Leia a página do manualfind
para mais detalhes.Cuidado que isso não é 100% infalível. Há chances de "falsos positivos". A maneira como o comando é escrito acima irá pular qualquer arquivo que possua qualquer diretório pai cujo nome esteja começando com
b
(positivo). Mas também ignorará qualquer arquivo cujo nome esteja começando,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.Presumo que você usou
a
eb
como espaços reservados e os nomes reais são mais parecidos comallosaurus
ebrachiosaurus
. Se você colocarbrachiosaurus
no lugarb
, a quantidade de falsos positivos será drasticamente reduzida.Pelo menos os falsos positivos será não excluído, por isso vai ser não tão trágico. Além disso, você pode verificar se há falsos positivos executando primeiro o comando sem
-delete
(mas lembre-se de colocar o implícito-depth
) e examine a saída.fonte
-not -path
foi exatamente isso! Obrigado por uma explicação generosa!-not -path
funciona enquanto-prune
não seria útil. Por que-not -path
coexistir-depth
?Basta usar em
rm
vez de-delete
:fonte
rm
funciona edelete
não funciona ?rm
não tem esse problema. Mas, independentemente, a elaboração seria uma coisa boa.-delete
implica-depth
, que obviamente não pode trabalhar com-prune
.-path
funciona, mas não parafind
de descer em diretórios que não precisam ser explorados.As respostas e explicações acima foram muito úteis.
Eu uso as soluções alternativas de "-exec rm {} +" ou "-not -path ... -delete ', mas essas podem ser muito mais lentas que" find ... -delete ". Eu já vi" find ... -delete "executa 5x mais rápido que" -exec rm {} + "em diretórios profundos em um sistema de arquivos NFS.
A solução '-not path "tem a sobrecarga óbvia de examinar todos os arquivos nos diretórios excluídos e abaixo.
O "find .. -exec rm {} +" chama rm, que faz chamadas de sistema:
O "find -delete" faz chamadas do sistema:
Portanto, o comando "-exec rm {} +" rm faz o caminho completo para a pesquisa de inode duas vezes por arquivo, mas "find -delete" faz uma estatística e desvincula o nome do arquivo no diretório atual. Essa é uma grande vitória quando você está removendo muitos arquivos em um diretório.
(modo de lamentação ativado (desculpe))
Parece que o design da interação entre -thp, -delete e -prune elimina desnecessariamente a maneira mais eficiente de executar a ação comum "excluir arquivos, exceto os diretórios -prune"
A combinação de "-type f -delete" deve poder ser executada sem -thpth, pois não está tentando excluir diretórios. Como alternativa, se "find" tivesse uma ação "-deletefile" que diz não excluir diretórios, -thp não precisaria ser implícito.
O comando xargs ou find -exec calls to rm pode ser acelerado se o rm tiver a opção de classificar nomes de arquivos, abrir diretórios e desassociar (dir_fd, filename) em vez de desvincular os caminhos completos. Ele já desassocia (dir_fd, nome do arquivo) ao recursar nos diretórios com a opção -r.
(modo de lamentação desativado)
fonte