Используя приведенное ниже дерево каталогов в качестве примера, как лучше всего переместить содержимое directory/folderA
к directory
.
Как перезаписать файл, если в месте назначения существует файл с таким же именем, например: directory/folderA/2017/06/info.log
и directory/2017/06/info.log
.
directory
|-- folderA
| |-- 2017
| | |-- 06
| |
| |-- 2016
| | |-- 12
| | |-- 11
| | |-- 10
|
|-- 2017
| |-- 04
| |-- 05
| |-- 06
|
|-- 2016
| |
Вы можете добиться этого с помощью cp -l
(--link
, файлы жестких ссылок вместо копирования):
cp -rfl folderA .
rm -rf folderA
В mv
просто перемещает, т.е. переименовывает каталог в ваш directory
. Для перемещения файлов в одной файловой системе mv
использует rename()
системный вызов. Если источник и цель были в разных файловых системах, mv
использовал бы cp
и rm
для выполнения перемещения, но сначала удаляет место назначения, копирует жестко связанные файлы (-R
), но не следует по символическим ссылкам (-P
):
rm -f destination_path && \ cp -pRP source_file destination && \ rm -rf source_file
Хотя вы не можете изменить это поведение mv
, то cp
Сама по себе команда более гибкая, и вам действительно стоит ее использовать. С участием cp
, то -f
вызывает удаление и создание отдельных файлов внутри места назначения вместо удаления сначала всего места назначения.
В cp
также ограничен, поскольку он может либо перезаписывать (-f
), хранитель (-n
) или спросите (-i
). Если вам нужно сравнить файлы, прежде чем решить, какой из них оставить, вам понадобится rsync
.
Если вам все еще нужно использовать rename()
системный вызов, но для достижения вашей цели по слиянию каталогов по желанию вам нужно будет написать сценарий, который вызывает отдельные rename()
s для отдельных файлов.
Сначала я создал ваше дерево каталогов с помощью
[root@localhost /tmp]# mkdir -pv directory/folderA/2017/06 directory/folderA/2016/{10..12} directory/2017/{04..06} directory/2016
Затем я создал ваши файлы примеров с помощью:
[root@localhost /tmp]# touch directory/{,folderA}/2017/06/info.log
Наконец, я использовал rsync с параметром --delete-after для перемещения вместо поведения по умолчанию rsync, которое вместо этого создавало бы копию:
[root@localhost /tmp]# rsync --delete-after -a directory/folderA/ directory
Примечание: завершающий '/' после исходного каталога (т.е. каталог / folderA / в отличие от каталога / folderA) требуется, если вы хотите, чтобы каталоги были удалены после их копирования.
Конечно, если вы действительно хотите ввести mv для получения желаемого поведения, вы можете создать собственную функцию оболочки. Я не сторонник этого, но это возможно. Небрежно, но возможно.
Вот пользовательская функция, которую вы можете добавить в свой ~ / .bashrc:
function mv() {
if [[ "$@" =~ .*--delete-after.*-av*.* ]]; then
rsync $@
else
command mv $@
fi; }
Затем вызовите обновленный ~ / .bashrc, выйдя из системы и снова войдя в систему -или-, набрав:
[root@localhost /tmp]# exec bash
Теперь вы можете протестировать свою пользовательскую функцию с помощью:
[root@localhost /tmp]# mv --delete-after -av directory/folderA/ directory
чтобы получить подробный вывод,
или с:
[root@localhost /tmp]# mv --delete-after -a directory/folderA/ directory
получать только ошибки, если они обнаружены.
Кроме того, вы также можете избежать передачи yes команде cp -rf, введя команду cp с предшествующей обратной косой чертой, например:
[root@localhost /tmp]# \cp -rf directory/folderA/* directory/
Причина, по которой вы указываете да, заключается в том, что у вас, вероятно, есть псевдоним для команды cp в вашем ~ / .bashrc, например:
[root@localhost /tmp]# alias cp='cp -i'
что вы можете проверить, набрав:
[root@localhost /tmp]# type cp