Хотя функциональность, которую вы ищете, недоступна в стоковом fdupes
, я форкнул fdupes
(мой форк называется jdupes
) и добавил некоторые возможности, которые могут решить эту проблему при определенных обстоятельствах. Например, в указанном случае, когда вы хотите сохранить somedirectory/subdirectory1/somefile
при автоудалении дубликатов (переключатели d
и N
вместе) и нет отдельных файлов непосредственно под somedirectory
, jdupes
может быть скормлен каждый непосредственный путь к подкаталогу с subdirectory1
сначала и переключателем -O
(который сортирует файлы по порядку параметров командной строки сначала):
jdupes -nrdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3
Это автоматически удалит все файлы, кроме одного, в наборе дубликатов и гарантирует, что если набор содержит файл в somedirectory/subdirectory1
, то он будет первым, тем самым автоматически становясь сохраненным файлом в наборе. В этом подходе все еще есть очевидные ограничения, например, тот факт, что другой дубликат в somedirectory/subdirectory1
может быть сохранен вместо того, который вы хотели сохранить, но в большом количестве случаев, подобных вашему, опция порядка параметров jdupes
в качестве обходного пути достаточно хороша.
В ближайшем будущем я планирую добавить систему фильтрации в jdupes
, которая позволит осуществлять огромный контроль над включением/исключением файлов, сохранением для действий -N
и применением таких "пачек фильтров" как на глобальной основе, так и на основе каждого параметра. Эта функция крайне необходима; я представляю себе нечто подобное для "автоматического удаления ненулевых дубликатов рекурсивно, НО всегда сохраняя somedirectory/subdirectory1/somefile
как есть":
jdupes -nrdN --filter=preserve: somedirectory/subdirectory1/somefile somedirectory/
Я думаю, что вы можете достичь своей цели с помощью следующей команды:
find Pictures -type f -print0 | xargs -0 mv -t Picturesnew
, где Pictures
— исходный каталог, а Picturesnew
— целевой каталог.
И mv
(, иcp
)имеют формат mv -t directory source...
, который хорошо подходит для использования с xargs
.
Но этот метод оставит файлы с повторяющимися именами на их исходных позициях (возможно, это неплохо, так как вы можете просмотреть их и скопировать в место назначения позже ), так какmv -t
не будет работать в интерактивном режиме при перенаправлении ввода используется . Это связано с тем, что xargs
уже считывает значения из перенаправленного стандартного ввода (, который является выходом find
), а mv
, который запускается xargs
, также пытается прочитать ответы из того же стандартного ввода. Таким образом, вы не можете использовать mv с каналами в интерактивном режиме.
Возможно, задание можно решить с помощью какого-нибудь умного ввода -переназначения дескриптора,но давайте попробуем более простой способ:избавиться от перенаправления вывода . Также мы не можем использовать -print0
в подстановке команд, потому что это не позволяет использовать 0 -байт. Нам нужно перебрать имена файлов с for
, , используя новую строку в качестве входного разделителя полей -:
TMP=$IFS;
IFS=$'\n';
for i in $(find Pictures -type f); do
mv -it../Picturesnew $i;
done;
IFS=$TMP
(вы можете скопировать его как один -вкладыш ).
В этом случае mv будет не только запрашивать у вас каждый дубликат, но и ждать ответа.
Я не знаю, почему при перезаписи не было подтверждения, которое должно присутствовать из-за параметра -i
в mv
. Но если предположить, что вы его не использовали и после операции был файл jpg Picturesnew
, как вы указываете в комментарии под своим вопросом, ну -вы перезаписали один и тот же файл 20000 раз.
xargs -0 -Imysongs mv -i mysongs./Picturesnew
Это означает, что для каждого аргумента будет выполняться эта команда:
mv -i argument./Picutesnew
Поскольку каталога ./Picturesnew
не было, команда mv
подумала, что вы имеете в виду, что она должна переместить файл сюда и переименовать в ./Picturesnew
. Так было 20000 раз.
После завершения работы конвейера должен остаться только один файл ./Picturesnew
. Последний, который был перемещен. Предыдущие ушли.
Таким образом, эта форма намного безопаснее:
mv -i argument./Picturesnew/
Это потому, что /
в конце устраняет путаницу в отношении того, что должно быть Picturesnew
.
Что касается -i
, вы не стали бы помещать его в этот пайплайн, так как он не будет работать. Он требует подтверждения.
find Pictures -type f -iname "*.jpg" -print0 | xargs -0 -I {} mv -n "{}" Picturesnew/
Было бы более синтаксически правильным решением, так что восстановите резервную копию и попробуйте.
Ты очень хотел
mkdir Picturesnew
find Pictures -type f -iname "*.jpg" -exec mv -i {} + Picturesnew/
mv не создает каталоги.
Параметр -i для mv приводит к тому, что он не работает при запуске в таком конвейере. (Хотя, с другой стороны, он, как мы надеемся, сказал mv не топать по всему первому файлу, переименованному в Picturesnew вместо того, каким он был изначально.)
В моем решении я предлагаю find перемещать несколько файлов на каждый экземпляр mv, если это полезно, чтобы свести к минимуму вероятность того, что ошибка, такая как оставление завершающего / off имени целевого каталога и отсутствие создания целевого каталога фактически переименовывает файл, а не генерирует желаемую ошибку. Это также имеет то преимущество, что позволяет mv фактически запрашивать подтверждение перезаписи файла, а не просто принимать следующее имя файла как «нет».