Como encontrar arquivos entre duas datas usando "find"?

21

Eu tenho uma conta de e-mail que já passou de 60 GB de e-mails e, atualmente, estou tendo muitos problemas ao usar um cliente de e-mail para arquivar e-mails do ano passado (2011).

Via terminal, estou tentando usar o find para localizar os arquivos entre 01-01-2011 e 31-12-2011, mas sem sucesso.

Como posso encontrar arquivos entre duas datas?

Se relevante, o objetivo final será um lote que moverá cada arquivo encontrado, correspondendo ao intervalo de datas, para uma pasta.

Zuul
fonte
@EliahKagan Na época, se a memória servir, nomes duplicados não eram um problema. No entanto, se você alimentar esse tempo, sempre serão apreciadas informações extras sobre um determinado assunto :) Além disso, votei na sua resposta, pois ela fornece informações adicionais sobre este tópico.
Zuul
@EliahKagan Nesse caso, encorajo-vos a dar uma resposta com a prática à prova de falhas que você destacou :)
Zuul

Respostas:

16

Você pode usar este script:

#!/bin/bash
for i in $(find Your_Mail_Dir/ -newermt "2011-01-01" ! -newermt "2011-12-31"); do
  mv $i /moved_emails_dir/
done
Octávio Filipe Gonçalves
fonte
6
A saída de findnão deve ser processada em um forloop de shell como este, exceto quando for garantido que nenhum arquivo tenha espaços em branco em seu nome. -exec,, -execdirou -print0 | xargsnormalmente deve ser usado; outra solução possível, que geralmente é muito menos desejável, mas permite que um forloop seja usado, é configurada temporariamente IFSpara que um espaço não seja reconhecido como um separador de campo.
Eliah Kagan
@EliahKagan, então como seria o comando então: Basta substituir findpor exec? Você se importaria de adicionar uma resposta que abordasse o uso de espaços .. ?? Muito apreciado.
precisa saber é o seguinte
3
@SherylHohman Não, não use o execcomando. Use um findcomando com a -execação a ser executada mv, ou o que você precisar executar, conforme descrito na resposta que eu publiquei . Quando find... -execexecuta seu comando com os nomes de caminho encontrados, ele não usa um shell, portanto, os espaços não acionam a divisão ou o globbing de palavras . (Você pode querer postar uma nova pergunta sobre o seu caso específico, ou para pedir exatamente o que você quer saber.)
Elias Kagan
@EliahKagan Desculpe, eu interpretei mal sua postagem - e que era de você ! Você é incrível! Sua postagem é Excelente .. e obrigado por responder, mesmo que tenha sido meu próprio erro ao ler !!
precisa saber é o seguinte
40

O Bash encontra arquivos entre duas datas:

find . -type f -newermt 2010-10-07 ! -newermt 2014-10-08

Retorna uma lista de arquivos com registro de data e hora após 07/10/2010 e antes de 08/10/2014

O Bash encontra arquivos de 15 minutos atrás até agora:

find . -type f -mmin -15

Retorna uma lista de arquivos com registro de data e hora após 15 minutos atrás, mas antes de agora.

O Bash encontra arquivos entre dois registros de data e hora:

find . -type f -newermt "2014-10-08 10:17:00" ! -newermt "2014-10-08 10:53:00"

Retorna arquivos com timestamps entre 2014-10-08 10:17:00e2014-10-08 10:53:00

Eric Leschinski
fonte
10

Movendo os arquivos e solicitando ao usuário quando houver nomes duplicados:

Como mostram as respostas de Subv3rsion e Eric Leschinski , o -newermtpredicado seleciona arquivos modificados mais recentemente que a data (e hora opcional) especificada como seu operando. Para encontrar arquivos

  • em qualquer lugar srcdir(incluindo seus subdiretórios, seus subdiretórios, etc.)
  • última modificação em (por exemplo) setembro de 2014
  • e mova-os paradestdir

...você pode correr:

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -i {} destdir/ \;

Em uma -execexpressão, find passa o nome do arquivo encontrado no lugar de {}. ;significa -execque o comando a ser executado e seus argumentos foram todos fornecidos (no caso de expressões subsequentes serem passadas para localizar -execos argumentos desse predicado em particular - veja abaixo um exemplo disso). ;deve ser escapado, \;para que não seja interpretado especialmente pelo shell. (Sem \, ;terminaria o findcomando inteiro , funcionando da mesma forma que uma nova linha. Mesmo que esse findcomando não tenha nada após essa -execexpressão, a falha em passar o ;argumento ainda é um erro de sintaxe.)

Se você apenas deseja listar os arquivos - o que é aconselhável se você não tiver certeza de como os emails antigos são armazenados ou quais outros arquivos podem estar presentes - omita -exece tudo à sua direita. (Para email, geralmente emails de datas diferentes são armazenados no mesmo arquivo; para alguém na situação descrita na pergunta aqui, recomendo investigar como eles são armazenados antes de mover qualquer arquivo.) Se você deseja imprimir os nomes e mover adicione -printantes -exec.

mv -i solicita sempre que um arquivo é substituído no destino, como aconteceria se:

  • existe um arquivo com o mesmo nome de um backup anterior ou
  • um arquivo com o mesmo nome, mas de um subdiretório diferente de srcdirjá foi movido durante a mesma findoperação, ou
  • (menos provável) um arquivo com o mesmo nome foi criado em algum lugar srcdirdurante a mesma findoperação, depois que o original foi movido, mas logo foi encontrado uma vez que findpercorre um subdiretório diferente.

Outras maneiras de chamar rm:

Você tem outras opções para lidar com arquivos com nomes duplicados.

  • Sem -i(ou seja ), normalmente não solicitaria aprovação, mas o faria se o arquivo de destino fosse somente leitura. ( pode até conseguir substituir um arquivo somente leitura às vezes, como se o usuário que o possui é o proprietário.)mv {} destdir/mvmv
  • Se você não deseja nem esse grau de interatividade e mvsempre deseja (tentar) substituir arquivos nomeados de forma idêntica, use mv -f.
  • Se, por outro lado, você quiser pular arquivos de origem quando já houver um arquivo de destino com o mesmo nome, use mv -n.
  • mvaceita os sinalizadores -be --backuppara renomear automaticamente arquivos nomeados de forma idêntica que já existem no destino. Por padrão, ~é adicionado para produzir o nome do backup e, se um arquivo com o nome e um arquivo com o nome do backup já existir no destino, o arquivo de backup será substituído. Esse padrão pode ser substituído por opções passadas ao chamar mve por variáveis ​​de ambiente. Veja man mvpara detalhes e o exemplo abaixo.

Movendo os arquivos e criando backups em caso de nomes duplicados:

Para mover todos os arquivos, faça backup de arquivos com nomes duplicados usando um ~sufixo e use sufixos numerados quando os arquivos já existirem (para evitar a substituição de qualquer coisa), execute:.~n~.~

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv --backup=existing {} destdir/ \;

Se você pulou arquivos com nomes duplicados e deseja saber quais:

Se você usa mv -ne deseja saber quais arquivos não foram movidos porque havia outro arquivo com o mesmo nome, a melhor maneira é provavelmente apenas executar o findcomando original novamente, sem -exece tudo à sua direita. Isso imprimirá seus nomes.
Ele também imprimirá os nomes de todos os arquivos correspondentes criados desde que você executou o find .... -exec ...comando original , mas para este aplicativo normalmente não haverá nenhum, pois você está procurando arquivos com tempos de modificação antigos. É possível atribuir a um arquivo um carimbo de data / hora da modificação anterior à sua idade real, com touche outros mecanismos, mas isso não parece provável que ocorra neste caso sem o seu conhecimento.

Saber imediatamente como os arquivos são ignorados devido a nomes duplicados:

mv -nnão relata nem retorna nenhum código de saída especial quando evita mover um arquivo. Portanto, se você quiser ser informado imediatamente dos arquivos ignorados durante a findexecução, precisará fazer uma etapa separada para isso. Uma maneira é:

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -n {} destdir/ \; \
    -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \; 

Algumas considerações técnicas provavelmente menores: Isso avisa incorretamente se mvnão conseguir copiar um arquivo por um motivo diferente do existente no destino e sair do relatório com êxito . Parece improvável, mas não tenho certeza de que seja impossível. Ele também potencialmente sofre uma condição de corrida : alertaria quando não houvesse nenhum erro real, se um novo arquivo com o mesmo nome fosse criado no mesmo local durante o período muito curto após a movimentação do arquivo antigo e antes da verificação para veja se foi removido. (Considerando o aplicativo, duvido que algum problema realmente ocorra.) Poderia ser reescrito para verificar o destino antesmovendo o arquivo em vez de depois: a condição de corrida se relacionaria aos arquivos de destino recém-criados, em vez dos arquivos de origem. E enquanto os erros e avisos relatados por findou mv(ou [, embora não deva haver) sejam gravados no erro padrão , nosso ...skipped (exists in...aviso é gravado na saída padrão . Normalmente, ambos aparecem no seu terminal, mas isso pode importar se você estiver usando scripts.

Dividi esse comando em duas linhas para facilitar a leitura. Pode ser executado dessa maneira ou você pode remover \a linha e a nova linha (ou seja, a quebra de linha).

Como esse findcomando funciona?

findpredicados podem ser testes (como -typee -newermt), usados ​​para seus valores de retorno ou ações (como -printe -exec), que são frequentemente usados ​​para seus efeitos colaterais.

Quando nenhum operador (como -afor e , -ofor ou ) é fornecido entre expressões, -aé implícito. findemprega avaliação de curto-circuito para e e ou . (ou seja, ) só é verdade se os p e q expressões são verdadeiras, então q não precisa ser avaliada se p é falsa. Embora muitas vezes não pensemos nisso nesses termos, é por isso que os testes precisam ser verdadeiros para ações ou testes subsequentes a serem avaliados. Por exemplo, suponha que se encontre um diretório. Ele é avaliado como falso, para que possa pular tudo depois.p qp -a qfind-type f

Como testes, as ações também são avaliadas como verdadeiras ou falsas. Dessa maneira, -execrelata se o comando executado saiu do relatório de sucesso (verdadeiro) ou falha (falso). Temos essa cadeia de -execexpressões conectada com implícita e :

-exec mv -n {} destdir/ \; -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;

Isso tenta mover o arquivo e, se mvrelatar falha, para. Não queremos avisar sobre um arquivo ignorado corretamente se outro problema foi o motivo pelo qual não foi movido.

Mas, se for bem-sucedido, ele executa o [comando . Como find, [suporta seu próprio tipo de expressões passadas como argumentos. [ -f {} ]verifica se o operando depois -f(passado para ele findno lugar de {}) existe (e é um arquivo regular) e retorna verdadeiro / sucesso ou falso / falha.
(O status de saída de muitos comandos é melhor interpretado como significando sucesso ou falha, mas [o status existente é geralmente melhor interpretado como verdadeiro ou falso.)

Se [retornado falso, o arquivo se foi e, por isso, foi movido, não sendo necessário fazer nada. Mas se [retornado falso, o arquivo ainda está lá. Em seguida, findavalia a próxima -execexpressão, que imprime a mensagem de aviso.

Leitura adicional

Eliah Kagan
fonte
Quando eu chegar a tempo, eu espero para adicionar uma seção sobre considerações de desempenho e -exec ... +com mv -t, em breve.
Eliah Kagan 9/10