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

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

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

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 possui a mesma extensão, a diferença é que possui (Copy)no final do nome

Quero obter todos esses arquivos e excluir o mais antigo e, eventualmente, renomear o arquivo de, por exemplo, file1 (Copy)para file1(ou seja, remover o (Copy)sufixo) se precisar ser renomeado.

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

Responder1

Estendidofind+bashsolução (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%/*}"- caminho do arquivo/caminho com nome de base cortado
  • bn="${0##*/}"- nome base do arquivo
  • main_bn="${bn/ (Copy)/}"- remova (Copy)a substring do nome base para obter oprincipal/comumnome base
  • if [ -f "$p/$main_bn" ]- se oprincipal/originalo arquivo existe (e é considerado um arquivo normal após a resolução do link simbólico)
    • t_copy_file=$(stat -c %Y "$0")- obter a hora da última modificação encontrada"cópia de"arquivo
    • t_main_file=$(stat -c %Y "$p/$main_bn")- obter a hora da última modificação deoriginalarquivo
    • if [[ $t_copy_file -gt $t_main_file ]]- se o"cópia de"arquivo é o recente - mova-o para ooriginalum (façaoriginal) commv "$0" "$p/$main_bn"
    • caso contrário - ooriginalarquivo é o recente, removendo "cópia de"arquivo comrm "$0"

Ou um pouco mais curto com -nto operador de teste de arquivo ( [ new­er­file –nt olderfile ]- verifique se newerfilefoi alterado mais recentemente que olderfileou se newerfileexiste e olderfilenão existe):

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' {} \;

Responder2

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á file (Copy) (Copy).txtarquivos primeiro.

  • **/: qualquer nível de subdiretório
  • N:nullglobexpandir para nada se não houver correspondência em vez de errar
  • D: inclui arquivos ocultos ( Darquivos ot) e desce para diretórios ocultos.
  • .: incluir apenasregulararquivos (sem diretório, fifo, dispositivo, link simbólico...)
  • $file:h:cabeçado arquivo (parte do diretório), como emcsh
  • $file:t:cauda(parte do nome do arquivo)
  • ${var/pattern/replacement}, aqui sem substituição
  • [[ ! -f $base || -L $base ]] ||...pule arquivos não regulares ou links simbólicos (mesmo que apontem para arquivos regulares) como proteção.
  • [ $file -nt $base ]: retorna verdadeiro se $filefoi modificado pela última vezdepois $base(ou $basenão está acessível, não devemos acontecer seguindo a verificação acima).

informação relacionada