LINUX.ORG.RU

Помогите осилить mv

 


0

1

Хочу переместить содержимое одного каталога в другой. И не выходит.

$ mkdir dir1
$ mkdir dir1/dir
$ touch dir1/dir/file1

$ mkdir dir2
$ mkdir dir2/dir
$ touch dir2/dir/file2

$ mv dir1/* dir2
mv: cannot move ‘dir1/dir’ to ‘dir2/dir’: File exists

Элементарный же пример — и такая неожиданность. Как это сделать?

★★

Ответ на: комментарий от tailgunner

Удалить один каталог и переименовать другой.

Мне надо, чтоб всё содержимое оказалось в dir2. А не только то, что было в dir1.

fffgh ★★
() автор топика
Ответ на: комментарий от tailgunner

Как мы видим, это не всегда возможно.

Типа, консоль пока не доросла до решения сложнейшей задачи объединения каталогов? Что-то сомневаюсь.

fffgh ★★
() автор топика

cannot move ‘dir1/dir’ to ‘dir2/dir’: File exists

тебе намекнули. очевидно.
Копирование и удаление каталога запрещено в этом примере?
К тому же это будет безопаснее, т.к. если что-то поёдет не так. Источник останется неубитым.

TomBOY ★★
()
Ответ на: комментарий от fffgh

Как мы видим, это не всегда возможно.

Типа, консоль пока не доросла до решения сложнейшей задачи объединения каталогов?

Типа, задача объединения двух каталогов несколько сложнее, чем тебе до сих пор кажется. Ты хотя бы подумал, как разрешать конфликты вида «одинаковые имена относятся к разным типам файлов»?

tailgunner ★★★★★
()

Всё что умеет mv:

Аргументы, обязательные для длинных ключей, обязательны и для коротких.
      --backup[=КОНТРОЛЬ]      создавать резервные копии целевых файлов
  -b                           то же, что и --backup, но без аргумента
  -f, --force                  переписывать существующие файлы не спрашивая
  -i, --interactive            спрашивать перед тем как переписывать
  -n, --no-clobber             не переписывать существующий файл
Если указано более одного ключа -i, -f, -n, то используется последний.
      --strip-trailing-slashes удаляет все конечные косые черты из каждого
                               аргумента ИСТОЧНИК
  -S, --suffix=СУФФИКС         перекрывает обычный суффикс для резервных копий
  -t, --target-directory=КАТАЛОГ переместить все ИСТОЧНИКИ в КАТАЛОГ
  -T, --no-target-directory    считать НАЗНАЧЕНИЕ обычным файлом
  -u, --update                 перемещать только, если ИСТОЧНИК
                               новее чем файл назначения, или когда файл
                               назначения отсутствует
  -v, --verbose                пояснять производимые действия
  -Z, --context                задать контекст безопасности SELinux файлу
                                 назначения как у типа по умолчанию
Так что cp или rsync

Deleted
()
Ответ на: комментарий от fffgh

Типа, консоль пока не доросла до решения сложнейшей задачи объединения каталогов?

Типа, в функционал mv не закладывалась задача мержить директории.

kravzo ★★
()
man rsync

С помощью mv мерджить директории не получится. Он не для этого.

anonymous
()
Ответ на: комментарий от TomBOY

тебе намекнули. очевидно.

Ну я понимаю, что ей не понравилось. Но зачем так? Любой FM это делает, а тут запрещено. Непонятно.

Копирование и удаление каталога запрещено в этом примере?

Не, как угодно можно сделать. Но копирование — всё-таки костыль. Вместо нескольких переименований придётся копипастить содержимое файлов.

К тому же это будет безопаснее

Ну это какой-то сильно суровый уровень надёжности. Я не ожидаю, что правильно вызванный mv (или что-то подобное) может упасть/отработать неверно.

Скорее предположу, что копирование не сработает, т.к. места не хватит.

fffgh ★★
() автор топика
Ответ на: комментарий от Mr_Alone

cp -a dir1/* dir2/ && rm -Rf dir1/*

Спасибо.

fffgh ★★
() автор топика
Ответ на: комментарий от tailgunner

как разрешать конфликты вида «одинаковые имена относятся к разным типам файлов»?

Можно пример?

fffgh ★★
() автор топика
Ответ на: комментарий от Deleted

Так что cp или rsync

Видимо, rsync.

fffgh ★★
() автор топика
Ответ на: комментарий от fffgh

Вместо нескольких переименований придётся копипастить содержимое файлов

Можно создавать жёсткие ссылки, у cp есть флаг --link.

xaizek ★★★★★
()
Ответ на: комментарий от tailgunner

dir1/foo файл.

dir2/foo каталог.

cp выдаёт предупреждение, каталог не трогает, но копирует всё остальное.

rsync заменяет каталог на файл.

Оба решения мне подходят, особенно второе. Т.е. никакой сложности тут нет, всё реализовано.

fffgh ★★
() автор топика
Ответ на: комментарий от xaizek

Можно создавать жёсткие ссылки, у cp есть флаг --link.

Ограничение на FS, но тоже вариант. Спасибо.

fffgh ★★
() автор топика

что тебя удивляет? В dir2 уже есть dir, то есть это имя уже существует в каталоге.

dikiy ★★☆☆☆
()
Ответ на: комментарий от fffgh

cp выдаёт [...]

rsync заменяет [...]

А что должен делать mv?

Т.е. никакой сложности тут нет, всё реализовано.

Ну да, причем реализовано двумя разными способами в двух разных программах. Ни одна из которых не переименовываетфайлы.

tailgunner ★★★★★
()
Ответ на: комментарий от dikiy

что тебя удивляет? В dir2 уже есть dir, то есть это имя уже существует в каталоге.

Есть, и что? Кидаем файлы из dir1/dir в dir2/dir, потом удаляем dir1/dir. cp так и делает, только не удаляет. Его почему-то не смущает, что dir2/dir уже есть.

fffgh ★★
() автор топика
Ответ на: комментарий от fffgh

потому (вангую) что ты cp ключ -R задал, и он рекурсивно заходит в каталоги. А mv такого не делает, он просто пытается перелинковать inode. Очевидно что эта операция быстрее намного делается чем копирование, однако ее сделать невозможно, если в каталоге назначения уже существует inode с таким же именем.

dikiy ★★☆☆☆
()
Ответ на: комментарий от tailgunner

А что должен делать mv?

Кстати, mv. Пишет предупреждение, пропускает foo и перемещает всё остальное.

Ну да, причем реализовано двумя разными способами в двух разных программах. Ни одна из которых не переименовываетфайлы.

Не рылся в мане cp или rsync, может там и переименовывание есть.

Меня устраивает поведение по умолчанию.

В общем, с задачей, «заменить каталог файлом», справляются все. А «скинуть содержимое в каталог с таким же названием» почему-то сложнее, mv этого не может.

fffgh ★★
() автор топика
Ответ на: комментарий от fffgh

А «скинуть содержимое в каталог с таким же названием» почему-то сложнее, mv этого не может.

mv - это команда переименования файлов. Если переименовать файл невозможно, она его не переименовывает. Не понимаю твоих претензий.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

нууу, вообще-то mv чуток сложнее действует. Она умеет так же и в пределах разных ФС работать, что в общем-то неочевидно.

dikiy ★★☆☆☆
()
Ответ на: комментарий от dikiy

нууу, вообще-то mv чуток сложнее действует. Она умеет так же и в пределах разных ФС работать

Не вижу, как это противоречит «переименованию файла». Никто не обещал, что переименование производится в пределах одной ФС.

tailgunner ★★★★★
()
Ответ на: комментарий от dikiy

Потому что переименование подразумевает перелинковку простую.

Единственное, что подразумевает переименование - это изменение имени. И всё.

tailgunner ★★★★★
()
Ответ на: комментарий от dikiy

А mv такого не делает, он просто пытается перелинковать inode. .. однако ее сделать невозможно, если в каталоге назначения уже существует inode с таким же именем.

Если dir2/dir пуст, то mv осиливает перемещение dir1/dir.

fffgh ★★
() автор топика
Ответ на: комментарий от tailgunner

Если переименовать файл невозможно, она его не переименовывает.

А почему в данном примере невозможно переименовать dir1/dir/file1 в dir2/dir/file1?

fffgh ★★
() автор топика
Ответ на: комментарий от fffgh

Не знаю, что такео «данный пример», но в хедпосте ясно написно mv: cannot move ‘dir1/dir’ to ‘dir2/dir’: File exists. Что там было дальше, мне неведомо.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Не знаю, что такео «данный пример»

Очевидно, тот что в шапке.

mv: cannot move ‘dir1/dir’ to ‘dir2/dir’: File exists

Ну дык «просто переименовать» и dir1/file в dir2/file не получится, там тоже «File exists». Сперва надо удалить dir2/file, затем переименовать dir1/file. С этим же mv справляется, т.е. он готов заниматься чем-то большим, чем переименование.

Что там было дальше, мне неведомо.

А дальше там могла бы быть попытка переместить файлы из dir1/dir, несмотря на то, что 'mv dir1/dir dir2' не удалось. Но её нет.

fffgh ★★
() автор топика

Либо rsync (но он будет копировать, затем удалять оригинал)

Либо сделать свой скриптик типа такого:

cd /path/to/source/ && find . -type d -exec mkdir -p "/path/to/dest/{}" \; ; find . -type f -exec mv "{}" "/path/to/dest/{}" \;
Tanger ★★★★★
()
Ответ на: комментарий от Tanger

Либо rsync (но он будет копировать, затем удалять оригинал)

А вот это я не догадался проверить. Если так, то rsync тоже плохое решение.

cd /path/to/source/ && find . -type d -exec mkdir -p "/path/to/dest/{}" \; ; find . -type f -exec mv "{}" "/path/to/dest/{}" \;

На каком символе это превращается в «format c:»? Щаз, сконцентрируюсь и попробую осилить, что тут написано.

fffgh ★★
() автор топика
Ответ на: комментарий от darkenshvein

почему?

В треде говорят, «потому что и не должно работать». Я тоже пока не понял, почему, но работаю над этим.

Пример простой, можно повторить и убедиться.

fffgh ★★
() автор топика
Ответ на: комментарий от darkenshvein

вот же: -f, -i, -n

Это не помогает.

Ну если только -i и отказаться от перезаписи dir2/dir. Тогда без ошибки и без перемещения dir1/dir/file1.

fffgh ★★
() автор топика
Ответ на: комментарий от fffgh

UPD: bugfix

А ещё можно что-то такое попробовать:

#!/bin/bash
src="$1"
dst="$2"
cmd_mv="echo mv" # remove echo
cmd_rmdir="echo rmdir" # remove echo
function processDir {
	local relativePathToDir="${1:${#src}}"
	local srcPath="${1}"
	local dstPath="$(sed 's|/*$||' <<< "$dst${relativePathToDir}")"
	if [ ! -d "$srcPath" ]; then
		echo "No such directory: $srcPath";
		exit
	fi
	if [ -d "$dstPath" ]; then
		for i in $(find "$srcPath/"* -maxdepth 1 -type d 2> /dev/null | sed 's|/*$||'); do
			processDir "${i}" || exit
		done;
		if [ "$(ls -1 "${srcPath}/" | wc -l)" -gt 0 ]; then
			$cmd_mv "${srcPath}"/* "${dstPath}/" || exit
		fi
		$cmd_rmdir "${srcPath}/" || exit
	else 
		$cmd_mv "${srcPath}" "${dstPath}" || exit
	fi
}

processDir "$src"

Tanger ★★★★★
()
Ответ на: UPD: bugfix от Tanger

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

А ещё можно что-то такое попробовать:

Примерно так и написал, только на питоне. Скрытые файлы и каталоги перемещает? (у меня да)

fffgh ★★
() автор топика
Ответ на: комментарий от darkenshvein

у меня скопировало все подкаталоги

И каталоги были такие, как в шапке?

dir1 исчез, а в dir2/dir лежит file1?

Что за OS, shell?

fffgh ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.