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 para
destdir
...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