Encontre arquivos com nomes semelhantes, exclua os mais antigos, renomeie os mais recentes

5

Eu tenho essa situação em que há muitos arquivos com nomes semelhantes (mas todos seguem um padrão) em diferentes subpastas

file1
file1 (Copy)
/folder1/file2.txt
/folder1/file2 (Copy).txt
/folder1/file3.png
/folder1/file3 (Copy).png

Cada arquivo está na mesma pasta de sua cópia e tem a mesma extensão, a diferença é que tem (Copy) no final do nome

Eu quero pegar todos esses arquivos e excluir o mais antigo e, por fim, renomear o arquivo de, por exemplo, file1 (Copy) to file1 (ou seja, remover o sufixo (Copy) ) se precisar ser renomeado .

Eu estava pensando em usar find e mv , mas não sei como dizer para mover a mais recente.

    
por valepu 22.11.2017 / 11:16

2 respostas

4

Solução estendida find + bash (também precisa da implementação GNU de stat ):

find . -type f -name "* (Copy).*" -exec bash -c 'p="${0%/*}"; bn="${0##*/}"; 
        main_bn="${bn/ (Copy)/}"; 
        if [ -f "$p/$main_bn" ]; then 
           t_copy_file=$(stat -c %Y "$0"); t_main_file=$(stat -c %Y "$p/$main_bn"); 
           if [[ $t_copy_file -gt $t_main_file ]]; then 
               mv "$0" "$p/$main_bn"; 
           else
               rm "$0"; 
           fi; 
        fi' {} \;
  • p="${0%/*}" - filepath / path com o nome de base aparado
  • bn="${0##*/}" - nome de base do arquivo
  • main_bn="${bn/ (Copy)/}" - remova (Copy) substring do nome da base para obter o nome de base main / common
  • if [ -f "$p/$main_bn" ] - se o arquivo main / original existir (e for considerado um arquivo regular após a resolução do symlink)
    • t_copy_file=$(stat -c %Y "$0") - obtenha a hora da última modificação do arquivo "copy" encontrado
    • t_main_file=$(stat -c %Y "$p/$main_bn") - obtenha a hora da última modificação do arquivo original
    • if [[ $t_copy_file -gt $t_main_file ]] - se o arquivo "copy" é recente - mova-o para o original (torne-o original ) com mv "$0" "$p/$main_bn"
    • caso contrário - o arquivo original é o mais recente, removendo o arquivo " cópia " com rm "$0"

Ou um pouco mais curto com -nt operador de teste de arquivo ( [ new­er­file –nt olderfile ] - verifique se newerfile foi alterado mais recentemente do que olderfile ou se newerfile existe e olderfile não):

find . -type f -name "* (Copy).*" -exec bash -c 'p="${0%/*}"; bn="${0##*/}"; 
        main_bn="${bn/ (Copy)/}"; 
        if [ -f "$p/$main_bn" ]; then 
           if [ "$0" -nt "$p/$main_bn" ]; then 
               mv "$0" "$p/$main_bn"; 
           else
               rm "$0"; 
           fi; 
        fi' {} \;
    
por 22.11.2017 / 12:04
4

Pode ser mais fácil com zsh :

setopt extendedglob # best in ~/.zshrc
for file (./**/?*" (Copy)"*(ND.)) {
  base=$file:h/${${file:t}/" (Copy)"}}
  [[ ! -f $base || -L $base ]] ||
    if [ $file -nt $base ]; then
      mv $file $base
    else
      rm -f $file
    fi
}

Você pode querer verificar se não há arquivos file (Copy) (Copy).txt primeiro.

  • **/ : qualquer nível de subdiretório
  • N : nullglob expande para nada se não houver correspondência em vez de errar
  • D : inclua arquivos ocultos ( D ot files) e desça para diretórios ocultos.
  • . : inclua apenas arquivos regulares (sem diretório, fifo, device, symlink ...)
  • $file:h : cabeça do arquivo (parte do diretório), como em csh
  • $file:t : tail (parte do nome do arquivo)
  • ${var/pattern/replacement} , aqui sem substituição
  • [[ ! -f $base || -L $base ]] ||... ignora arquivos não regulares ou links simbólicos (mesmo se eles apontarem para arquivos regulares) como uma proteção.
  • [ $file -nt $base ] : retorna verdadeiro se $file foi modificado pela última vez após $base (ou $base não está acessível, não devemos acontecer após a verificação acima).
por 22.11.2017 / 12:19