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

Хотя функциональность, которую вы ищете, недоступна в стоковом 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/

0
05.03.2019, 16:20
4 ответа

Я думаю, что вы можете достичь своей цели с помощью следующей команды:

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 будет не только запрашивать у вас каждый дубликат, но и ждать ответа.

0
28.01.2020, 02:30

Я не знаю, почему при перезаписи не было подтверждения, которое должно присутствовать из-за параметра -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, вы не стали бы помещать его в этот пайплайн, так как он не будет работать. Он требует подтверждения.

1
28.01.2020, 02:30
find Pictures -type f -iname "*.jpg" -print0 | xargs -0 -I {} mv -n "{}" Picturesnew/

Было бы более синтаксически правильным решением, так что восстановите резервную копию и попробуйте.

0
28.01.2020, 02:30

Ты очень хотел

mkdir Picturesnew
find Pictures -type f -iname "*.jpg" -exec mv -i {} + Picturesnew/

mv не создает каталоги.

Параметр -i для mv приводит к тому, что он не работает при запуске в таком конвейере. (Хотя, с другой стороны, он, как мы надеемся, сказал mv не топать по всему первому файлу, переименованному в Picturesnew вместо того, каким он был изначально.)

В моем решении я предлагаю find перемещать несколько файлов на каждый экземпляр mv, если это полезно, чтобы свести к минимуму вероятность того, что ошибка, такая как оставление завершающего / off имени целевого каталога и отсутствие создания целевого каталога фактически переименовывает файл, а не генерирует желаемую ошибку. Это также имеет то преимущество, что позволяет mv фактически запрашивать подтверждение перезаписи файла, а не просто принимать следующее имя файла как «нет».

1
28.01.2020, 02:30

Теги

Похожие вопросы