
У меня есть два каталога, которые нужно объединить. Файлы в этих двух каталогах все большие (>= 500 МБ).
Что я хочу архивировать: Для файлов в исходном каталоге: если их нет в целевом каталоге, mv
то в целевой каталог (что быстро, поскольку мы по сути создаем новую жесткую ссылку и отменяем связь с исходным файлом); если они есть в целевом каталоге, то копируем туда исходный файл и удаляем исходный файл.
Наиболее распространенный способ объединения каталогов в системе Linux — использование опции rsync
with --remove-source-files
. Но это медленно, поскольку операция копирования будет выполнена даже если файл назначения не существует.
Есть идеи получше? Спасибо.
решение1
В основном то, что Вы описали, это перемещение файлов в место назначения перезаписи, если оно существует. Так что просто переместите их.
решение2
Есть случай, когда mv
не удается. Вот некоторые примеры данных:
mkdir -p src/d dest/d
touch src/d/f1 dest/d/f2
Посмотрите, как это mv
не удается:
$ mv src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -f src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fv src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fvi src/* dest/
mv: overwrite 'dest/d'? y
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fvi -t dest/ src/*
mv: overwrite 'dest/d'? y
mv: cannot move 'src/d' to 'dest/d': Directory not empty
Итак, создайте файл скрипта:
vim supermove
Этот пример не проверяет ошибки (ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: у меня работает, но, пожалуйста, проверьте, работает ли он у вас... возможно, с echo
before mv
), и перезапишет файлы с тем же путем. И он использует find с, \;
что ужасно неэффективно, но +
не работает правильно с "$dest"
prepended. Более старые версии будут создавать некоторые каталоги без пути, а более новые версии find выдадут:
find: In '-exec ... {} +' the '{}' must appear by itself, but you specified 'dest/{}'
Хотя, возможно, вы сможете найти способ исправить это с помощью xargs. (Это заняло несколько минут на файлах 64k и 8TB, которые я перемещал). Добавьте этот контент:
#!/bin/bash
src=$1
dest=$2
src=$(readlink -f "$src")
dest=$(readlink -f "$dest")
cd "$src"
# also copy hidden files
shopt -s dotglob
# make dirs (missing old permission,acl,xattr data), and then mv the files
time find * -type d -exec mkdir -p "$dest"/{} \;
time find * -type f -exec mv {} "$dest"/{} \;
# also copy permissions, acls, xattrs
rsync -aAX "$src"/ "$dest"/
И сделайте его исполняемым:
chmod +rx supermove
И запустите его.
./supermove src/ dest/
И результат... до:
$ find src dest
src/
src/d
src/d/f1
dest/
dest/d
dest/d/f2
После:
$ find src dest
src
src/d
dest
dest/d
dest/d/f1
dest/d/f2
Теперь src/
должны быть только пустые директории. Если так, то можно rm -r src
почистить.
решение3
mv
Все варианты направлены на разрешение конфликтов:
Выбери один:
-f force (always overwrite)
-i interactive (ask whether to overwrite)
-n no clobber (no overwrite)
И это тоже хорошо:
-v verbose
В противном случае данные могут потеряться и/или будет непонятно, что именно произошло.
mv также лучше на той же fs, потому что он просто обновляет inode каталога, файлы не должны портиться. Другое дело, что чем больше операция, тем больше вероятность, что что-то пойдет не так, например, возникнут программные ошибки.