Movendo os arquivos e solicitando ao usuário quando houver nomes duplicados:
Como mostram as respostas de Subv3rsion e Eric Leschinski , o -newermt
predicado 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 -exec
expressão, find passa o nome do arquivo encontrado no lugar de {}
. ;
significa -exec
que o comando a ser executado e seus argumentos foram todos fornecidos (no caso de expressões subsequentes serem passadas para localizar -exec
os 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 find
comando inteiro , funcionando da mesma forma que uma nova linha. Mesmo que esse find
comando não tenha nada após essa -exec
expressã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 -exec
e 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 -print
antes -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
srcdir
já foi movido durante a mesma find
operação, ou
- (menos provável) um arquivo com o mesmo nome foi criado em algum lugar
srcdir
durante a mesma find
operação, depois que o original foi movido, mas logo foi encontrado uma vez que find
percorre 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/
mv
mv
- Se você não deseja nem esse grau de interatividade e
mv
sempre 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
.
mv
aceita os sinalizadores -b
e --backup
para 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 mv
e por variáveis de ambiente. Veja man mv
para 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 -n
e deseja saber quais arquivos não foram movidos porque havia outro arquivo com o mesmo nome, a melhor maneira é provavelmente apenas executar o find
comando original novamente, sem -exec
e 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 touch
e 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 -n
nã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 find
execuçã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 mv
nã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 find
ou 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 find
comando funciona?
find
predicados podem ser testes (como -type
e -newermt
), usados para seus valores de retorno ou ações (como -print
e -exec
), que são frequentemente usados para seus efeitos colaterais.
Quando nenhum operador (como -a
for e , -o
for ou ) é fornecido entre expressões, -a
é implícito. find
emprega 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 q
p -a q
find
-type f
Como testes, as ações também são avaliadas como verdadeiras ou falsas. Dessa maneira, -exec
relata se o comando executado saiu do relatório de sucesso (verdadeiro) ou falha (falso). Temos essa cadeia de -exec
expressõ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 mv
relatar 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 find
no 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, find
avalia a próxima -exec
expressão, que imprime a mensagem de aviso.
Leitura adicional