Как рекурсивно переместить файл в зависимости от размера и сохранить структуру

Как рекурсивно переместить файл в зависимости от размера и сохранить структуру

Я хочу переместить файлы размером более «300 Мб» из одного дерева каталогов, где каждый файл находится в подпапках

Пример: У меня есть структура каталогов:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

Вот ожидаемый результат — «перемещение» дерева каталогов, при котором каждый файл перемещается в подпапки:

dirB/            #  normal directory
dirB/file1       #  moved from dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  moved from dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  moved from dirA/y/file3

Но find /path/ -type f -size +300mчто потом? И, к сожалению, некоторые файлы содержат всевозможные символы, которые вы можете найти на своей клавиатуре.

Я смотрел на этонитьгде кто-то говорит о cpioпрограмме, о которой я не знаю...

PS: установлен ли GNU Parallel, может ли это ускорить работу?

решение1

Самый простой способ — сзш. Вы можете использоватьквалификаторы globдля сопоставления файлов по таким критериям, как их тип и размер.шаблон подстановочных знаков **/соответствует любому уровню подкаталогов.модификаторы истории hи tявляются простыми способами извлечения каталога и базовой части имени файла. Вызовите mkdir -pдля создания каталогов, когда это необходимо.

cd dirA
for x in **/*(.Lm+300); do
  mkdir -p ../dirB/$x:h &&
    mv -- $x ../dirB/$x
done

Портативный способ — с помощью find. Используйте -execдля вызова фрагмента оболочки для каждого файла.

cd dirA
find . -type f -size +300000k -exec sh -c 'for x do
  mkdir -p "../dirB/${x%/*}"
  mv "$x" "../dirB/$x"
done' sh {} +

Распараллеливание редко бывает полезным для ввода/вывода: оно позволяет использовать преимущества нескольких ЦП, но ЦП редко становится узким местом при вводе/выводе.

решение2

Perl rename— очевидный выбор. Он может быть установлен как ren, rename, или pren:

find dirA -type f -size +300M | ren 's:^dirA/:dirB/:'

Однако это не сработает, если файлы перемещены в другую точку монтирования, и не сработает, если каталоги отсутствуют.

GNU Parallel будет работать медленнее:

cd dirA
find . -type f -size +300M | parallel mkdir -p ../dirB/{//}
find . -type f -size +300M | parallel mv {} ../dirB/{}

но будет работать, даже если для переноса файлов в другую файловую систему потребуется выполнить процедуру копирования и удаления.

решение3

Суммируя:

find dirA -type f -size +300m -printf "mv %p dirB/%P\n" | sh

Но все подкаталоги в dirB должны существовать до того, как вы начнете. По этой причине я предлагаю вам выполнить следующие два шага:

cd dirA
find . -type f -size +300m -printf "mkdir -p ../dirB/%h\nmv %p ../dirB/%P\n" | sh

Относительно cpio (на самом деле он решает проблему с подкаталогами):

(cd dirA; find . -type f -size +300m) | cpio -p -md  dirB

(Что касается cp(1) в той же теме, которую вы упомянули, то это нехорошо для вас, потому что он будет копировать все файлы и построить подкаталог с именем dirA в dirB. Флагможет решить эту проблему)

решение4

Этого должно хватить.

find /path -type f -size +300m | while read A ; do DEST=${A/dirA/dirB} ; echo mkdir -p $(dirname $DEST) 2>/dev/null; echo mv $A $DEST ; done

Сначала запустите его как есть, проверьте работоспособность, и если вас устраивают предложенные команды, запустите его повторно без echoэлементов.

В вашем примере структуры файла будут сгенерированы следующие команды:

mkdir -p ./dirB
mv ./dirA/file1 ./dirB/file1
mkdir -p ./dirB/x
mv ./dirA/x/file2 ./dirB/x/file2
mkdir -p ./dirB/y
mv ./dirA/y/file3 ./dirB/y/file3

Связанный контент