it-swarm-ru.tech

Как перезаписать целевые файлы с помощью mv?

У меня есть тонна файлов и каталогов в подкаталоге, который я хочу переместить в родительский каталог. В целевом каталоге уже есть несколько файлов и каталогов, которые необходимо перезаписать. Файлы, которые присутствуют только в цели, должны быть оставлены нетронутыми. Могу ли я заставить mv сделать это? Это (mv * ..) жалуется

mv: cannot move `xyz' to `../xyz': Directory not empty

Что мне не хватает?

175
EricSchaefer

Вам нужно будет скопировать их в место назначения, а затем удалить источник, используя команды cp -r * .. с последующим rm -rf *.

Я не думаю, что вы можете "объединить" каталоги, используя mv.

128
dogbane

rsync, вероятно, будет лучшим вариантом здесь. Это так же просто, как rsync -a subdir/ ./.

Мое тестовое дерево в формате filename: contents:

./file1:root
./file2:root
./dir/file3:dir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

Запуск rsync:

$ rsync -a -v subdir/ ./
sending incremental file list
./
file1
dir/
dir/file3

Дает:

./file1:subdir
./file2:root
./dir/file3:subdir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

И затем, чтобы эмулировать mv, вы, вероятно, захотите удалить исходный каталог:

$ rm -r subdir/

Предоставление:

./file1:subdir
./file2:parent
./dir/file3:subdir
./dir/file4:dir

Если это не так, можете ли вы привести аналогичный пример (например, используя мое тестовое дерево в верхней части этого ответа) с желаемым результатом?

77
Mikel

rsync может удалить источник после копирования с помощью --remove-source-files параметр. Это должен быть удобный способ сделать то, что вы хотите.

От rsync man page:

        --remove-source-files   sender removes synchronized files (non-dir)
52
Mike Chen

Вы можете сделать это с помощью cp и ​​rm, но не копируя огромное количество данных, которые вы (предположительно) пытаетесь избежать передачи. @mattdm упомянул об этом в его комментарий и ответ на другой вопрос более полно обсуждает различные варианты.

cp -rlf source destination
rm -r source

По сути, опция -l для команды cp создает жесткие ссылки на файлы, а не копирует их данные в новые файлы.

24
palswim

Вот скрипт, который перемещает файлы из-под /path/to/source/root к соответствующему пути под /path/to/destination/root.

  • Если каталог существует как в источнике, так и в месте назначения, содержимое рекурсивно перемещается и объединяется.
  • Если файл или каталог существует в источнике, но не в месте назначения, он перемещается.
  • Любой файл или каталог, который уже существует в месте назначения, остается позади. (В частности, объединенные каталоги остаются в источнике. Это не легко исправить.)

Осторожно, непроверенный код.

export dest='/path/to/destination/root'
cd /path/to/source/root
find . -type d \( -exec sh -c '[ -d "$dest/$0" ]' {} \; -o \
                  -exec sh -c 'mv "$0" "$dest/$0"' {} \; -Prune \) \
    -o -exec sh -c '
        if ! [ -e "$dest/$0" ]; then
          mv -f "$0" "$dest/$0";
        fi
' {} \;
9
Gilles 'SO- stop being evil'

Эта тема существует уже много лет и по-прежнему занимает первое место в Google, поэтому я хотел добавить еще один метод. Как я обычно это делаю: упаковываю содержимое subdir в tarball, перемещаем tarball в родительский каталог и затем извлекаю его с поведением по умолчанию --overwrite. Это именно то, что вы ищете. После этого вы можете удалить свой subdir.

cd xyz
tar -cvzpf tmp.tar.gz *
mv tmp.tar.gz ../tmp.tar.gz
cd ..
tar -xvzpf tmp.tar.gz
rm -rf xyz
rm -f tmp.tar.gz
3
Simon Kraus

Если у вас достаточно памяти, вы можете сделать это следующим образом:

mv -bfv directory_1/* directory_2/ # all duplicate source files/directories 
                                   # will have ~ appended to them
find -name "*~" -delete            # will recursively find and delete all files 
                                   # with ~ on the end

Убедитесь, что нет важных файлов с ~ в конце, но если они есть, вы можете добавить --suffix=whateveryouwant вместо значения по умолчанию.

0
4D3H2