Найти файлы с похожими именами, удалить самые старые, переименовать самые новые

Найти файлы с похожими именами, удалить самые старые, переименовать самые новые

У меня такая ситуация, когда в разных подпапках находится много файлов с похожими именами (но все они следуют шаблону)

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

Каждый файл находится в той же папке, что и его копия, и имеет то же расширение, разница в том, что (Copy)в конце имени есть

Я хочу получить все эти файлы и удалить самый старый из них, а затем в конечном итоге переименовать файл, например, file1 (Copy)в file1(то есть удалить (Copy)суффикс), если его необходимо переименовать.

Я думал использовать findи , mvно не уверен, как заставить его переместить самый последний.

решение1

Расширенныйfind+bashрешение (также необходима реализация GNU 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%/*}"- путь к файлу/путь с обрезанным базовым именем
  • bn="${0##*/}"- базовое имя файла
  • main_bn="${bn/ (Copy)/}"- удалить (Copy)подстроку из базового имени, чтобы получитьосновной/общийбазовое имя
  • if [ -f "$p/$main_bn" ]- еслиосновной/оригинальныйфайл существует (и оказывается обычным файлом после разрешения символической ссылки)
    • t_copy_file=$(stat -c %Y "$0")- получить время последнего изменения найденного"копия"файл
    • t_main_file=$(stat -c %Y "$p/$main_bn")- получить время последнего измененияоригинальныйфайл
    • if [[ $t_copy_file -gt $t_main_file ]]- если"копия"файл последний - переместите его воригинальныйодин (сделай этооригинальный) сmv "$0" "$p/$main_bn"
    • в противном случае -оригинальныйфайл последний, удаляющий "копия"файл сrm "$0"

Или немного короче с -ntоператором проверки файла ( [ new­er­file –nt olderfile ]- проверяет, newerfileбыл ли изменен позже, чем olderfile, или newerfileсуществует и olderfileне существует):

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

решение2

Это может быть проще с 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
}

Возможно, вам сначала захочется проверить, нет ли там file (Copy) (Copy).txtфайлов.

  • **/: любой уровень подкаталога
  • N:нульглобрасширяется до нуля, если нет совпадений, вместо того, чтобы выдавать ошибку
  • D: включить скрытые файлы ( Dфайлы ot) и перейти в скрытые каталоги.
  • .: только включитьобычныйфайлы (без каталога, fifo, устройства, символической ссылки...)
  • $file:h:головафайла (часть каталога), как вcsh
  • $file:t:хвост(часть имени файла)
  • ${var/pattern/replacement}, здесь без замены
  • [[ ! -f $base || -L $base ]] ||...в качестве меры предосторожности пропускайте нестандартные файлы или символические ссылки (даже если они указывают на стандартные файлы).
  • [ $file -nt $base ]: возвращает true, если $fileпоследний раз был измененпосле $base(или $baseнедоступен, не должно произойти после проверки выше).

Связанный контент