У меня такая ситуация, когда в разных подпапках находится много файлов с похожими именами (но все они следуют шаблону)
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
оператором проверки файла ( [ newerfile –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
недоступен, не должно произойти после проверки выше).