
Я хочу переместить файлы размером более «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