Назад | Перейти на главную страницу

Утилита рекурсивного перемещения в Unix?

Иногда у меня есть два дерева, которые раньше имели одинаковый контент, но выросли не синхронно (потому что я перемещал диски или что-то еще). Хорошим примером является дерево, в котором я зеркалирую исходные пакеты Fedora.

Я хочу снова объединить эти два дерева, переместив все файлы из tree1 в tree2.

Обычно я делаю это с помощью:

rsync -arv tree1/* tree2

Затем удалите tree1.

Однако на это уходит очень много времени и места на диске, и было бы гораздо проще сделать:

mv -r tree1/* tree2

Другими словами, рекурсивный ход. Это было бы быстрее, потому что, во-первых, он даже не копировал бы, просто перемещал inodes, а во-вторых, мне не нужно было бы удалять в конце.

Это существует?

В качестве тестового примера рассмотрим следующую последовательность команд:

$ mkdir -p a/b
$ touch a/b/c1
$ rsync -arv a/ a2
sending incremental file list
created directory
./
b/
b/c1
b/c2

sent 173 bytes  received 57 bytes  460.00 bytes/sec
total size is 0  speedup is 0.00
$ touch a/b/c2

Какая команда теперь будет иметь эффект перемещения a / b / c2 в a2 / b / c2 с последующим удалением поддерева a (поскольку все в нем уже находится в дереве назначения)?

предлагаемый mv -uf dir1/* dir2/ перемещайте (под) каталоги, а не каждый файл. вы можете попробовать использовать find

cd dir1
find . -type d -exec mkdir -p dir2/"{}" \;
find . -type f -exec mv -uf "{}" dir2/"{}" \;

или что-то подобное

Согласно справочной странице mv (1) от GNU mv:

-u, --update move only when the SOURCE file is newer than the destination file or when the destination file is missing

Не

mv -uf tree1/* tree2/

работай?

Midnight Commander (mc) тоже хорош для такого рода вещей. Пометьте файлы с помощью CTRL-t, нажмите F6, и когда он попросит перезаписать целевые файлы, выберите «Обновить», если вы хотите перезаписать старые файлы.

Вы можете использовать "cp -l & rm" для перемещения внутри устройства:

cp -alv --backup=numbered tree1/* tree2 &&
rm -rf tree1/
  • -l из cp использовать жесткие ссылки вместо копирования (это также предотвращает операции между устройствами)
  • --backup=numbered из cp для резервного копирования существующих файлов в целевом каталоге

И будьте осторожны с этими двумя проблемами:

  • использовать && чтобы предотвратить удаление ваших нескопированных данных, если вы случайно запустите его на разных устройствах. (в корпусе корсса cp выходит со статусом "1", по крайней мере, для GNU coreutils)
  • файлы, начинающиеся с "." в tree1, вы потеряете их, если они есть.

Ответ Хавьера с помощью find работает хорошо, за исключением того, что он не удаляет исходные каталоги. Добавьте в конце:

rmdir $(find . -type d  |grep -v ^\.$)

ошибаться

mv dir1/* dir2/

или просто

rsync -arv --remove-source-files  tree1/* tree2

должно быть достаточно, вы, вероятно, столкнетесь с проблемами в какой-то момент, когда слишком много записей в dir1.

find sourcedir -maxdepth 1 -exec echo mv {} targetdir/ \;

должны быть хорошие варианты

find sourcedir -maxdepth 1 -print0 |xargs -0 -I _ echo mv _ targetdir
find sourcedir -maxdepth1 -exec mv {} targetdir/ +

оба на самом деле не нужны, потому что mv просто принимает 2 варианта (исходная цель), поэтому в этом случае вам придется жить с множеством процессов.

cd /tree1
mv * /tree2 

Это не будет перемещать скрытые файлы или папки, но и ваш исходный пример тоже.

Я думаю, МВ не делает то, что ты думаешь.

Файловая система unix состоит из 3 компонентов:

  • записи каталога
  • inodes
  • блоки

Запись каталога указывает на индексный дескриптор.

В индексном дескрипторе есть метатаданные о файле (это файл, каталог, именованный канал? Кто им владеет? Какие разрешения? Какие блоки использует этот индексный дескриптор?

Блоки - это вещи, которые фактически содержат содержимое файла.

Итак - когда вы "mv" файл, все, что вы на самом деле делаете, это отсоединяете первую запись каталога и повторно связываете ее в другом месте.

snoopy -> inode 333 
woodstock -> inode 333

Никакие данные никогда не дублируются / копируются. Вы создаете ссылку snoopy, затем вы создаете ссылку woodstock, а затем удаляете ссылку snoopy. (с каталогами дела обстоят немного иначе, потому что обычно вы не можете создавать каталоги с жесткой связью, но даже в этом случае имя "ссылки" просто меняется).

Что делать, если вы переходите с одной файловой системы на другую? Раньше mv просто выдавал ошибку и явно указывал, что вы не можете переместить файл из одной файловой системы в другую. В эти дни кажется, что я тихо копии данные затем удаляют оригинал.

Раньше, поскольку вы не могли перемещать данные из одной файловой системы в другую, вы привыкли использовать идиомы вроде

tar -cf -. | (cd / new / location && tar -xf -)

затем вы удаляете старые данные. Отчасти причиной использования tar было то, что раньше cp уничтожал такие метаданные, как «это символическая ссылка» и «это жесткая ссылка», и вместо этого вы просто получали бы новые копии этого файла как обычные файлы. Тем не менее, вам нужно указать флаги «cp», чтобы сообщить ему, чтобы он сохранял такую ​​структуру.

Невозможно избежать «перемещения» большого количества данных из одной файловой системы в другую. Неважно, используете ли вы новый ход, rsync, tar или cpio.

Но если вы храните все данные в одной файловой системе, это:

mv / файловая система-1 / большой / каталог * / файловая система-1 / большой2 /

это будет очень быстро, потому что это просто изменяет записи каталога, а не перемещает реальные данные.

Возникают и другие проблемы, например, что делать, если файл / каталог уже существует в новом месте, а также в исходном местоположении?

переключитесь в каталог, который хотите переместить, и выполните

tar cf - * | ( cd /target; tar xfp -)

Быстрее, чем мв ...