У мене є великий каталог, що містить підкаталоги та файли, які я хочу копіювати рекурсивно.
Чи є спосіб сказати, cp
що він повинен виконувати операцію копіювання в порядку розміру файлу, щоб найменші файли були скопійовані спочатку?
У мене є великий каталог, що містить підкаталоги та файли, які я хочу копіювати рекурсивно.
Чи є спосіб сказати, cp
що він повинен виконувати операцію копіювання в порядку розміру файлу, щоб найменші файли були скопійовані спочатку?
Відповіді:
Це робить всю роботу за один раз - у всіх дочірніх каталогах, і все в одному потоці без проблем із іменем файлу. Він буде копіювати з найменшого до найбільшого кожного файлу, який у вас є. Вам знадобиться, mkdir ${DESTINATION}
якщо його ще не існує.
find . ! -type d -print0 |
du -b0 --files0-from=/dev/stdin |
sort -zk1,1n |
sed -zn 's/^[^0-9]*[0-9]*[^.]*//p' |
tar --hard-dereference --null -T /dev/stdin -cf - |
tar -C"${DESTINATION}" --same-order -xvf -
Ви знаєте що, хоча? Це не робить порожні довідні каталоги. Я міг би зробити деяке перенаправлення через цей трубопровід, але це лише умова гонки, яка чекає, що це станеться. Найпростіший, мабуть, найкращий. Тож просто зробіть це згодом:
find . -type d -printf 'mkdir -p "'"${DESTINATION}"'/%p"\n' |
. /dev/stdin
Або, оскільки Гілл дуже добре вказує на свою відповідь щодо збереження дозволів каталогів, я також повинен спробувати. Я думаю, що це зробить це:
find . -type d -printf '[ -d "'"${DESTINATION}"'/%p" ] ||
cp "%p" -t "'"${DESTINATION}"'"\n' |
. /dev/stdin
Я б хотів зробити ставку, що це швидше, ніж mkdir
все одно.
Ось швидкий і брудний метод використання rsync
. Для цього прикладу я вважаю що-небудь менше 10 Мб "маленьким".
Спочатку передайте лише невеликі файли:
rsync -a --max-size=10m srcdir dstdir
Потім перенесіть решта файлів. Передані раніше невеликі файли не будуть повторно скопійовані, якщо вони не були змінені.
rsync -a srcdir dstdir
З man 1 rsync
--max-size=SIZE
This tells rsync to avoid transferring any file that is larger
than the specified SIZE. The SIZE value can be suffixed with a
string to indicate a size multiplier, and may be a fractional
value (e.g. "--max-size=1.5m").
This option is a transfer rule, not an exclude, so it doesn’t
affect the data that goes into the file-lists, and thus it
doesn’t affect deletions. It just limits the files that the
receiver requests to be transferred.
The suffixes are as follows: "K" (or "KiB") is a kibibyte
(1024), "M" (or "MiB") is a mebibyte (1024*1024), and "G" (or
"GiB") is a gibibyte (1024*1024*1024). If you want the multi‐
plier to be 1000 instead of 1024, use "KB", "MB", or "GB".
(Note: lower-case is also accepted for all values.) Finally, if
the suffix ends in either "+1" or "-1", the value will be offset
by one byte in the indicated direction.
Examples: --max-size=1.5mb-1 is 1499999 bytes, and
--max-size=2g+1 is 2147483649 bytes.
Звичайно, порядок передачі файлів за файлом не суворо найменший до найбільшого, але я думаю, що це може бути найпростіше рішення, яке відповідає духу ваших вимог.
--copy-dest=DIR
та / або --compare-dest=DIR
я думаю. Я тільки знаю , тому що я повинен був додати --hard-dereference
себе tar
після розміщення мій власний відповідь , тому що мені не вистачає посилань. Я думаю, що rsync
насправді він поводиться більш специфічно для локальних файлових систем з тими, хто все одно - я використовував його за допомогою USB-ключів, і він затопить шину, якщо не встановити обмеження пропускної здатності. Я думаю, що я повинен був використовувати будь-який з цих інших замість цього.
Не cp
безпосередньо, це далеко за її можливостями. Але ви можете домовитись зателефонувати cp
по файлам у потрібному порядку.
Zsh зручно дозволяє сортувати файли за розміром за допомогою глобального класифікатора . Ось фрагмент zsh, який копіює файли у порядку збільшення розміру з-під /path/to/source-directory
під /path/to/destination-directory
.
cd /path/to/source-directory
for x in **/*(.oL); do
mkdir -p /path/to/destination-directory/$x:h
cp $x /path/to/destination-directory/$x:h
done
Замість циклу ви можете використовувати zcp
функцію. Однак вам потрібно створити спочатку каталоги призначення, які можна зробити в криптовалютній лінійці.
autoload -U zmv; alias zcp='zmv -C'
cd /path/to/source-directory
mkdir **/*(/e\''REPLY=/path/to/destination-directory/$REPLY'\')
zcp -Q '**/*(.oL)' '/path/to/destination-directory/$f'
Це не зберігає право власності на вихідні каталоги. Якщо ви цього хочете, вам потрібно зареєструвати відповідну програму копіювання, наприклад, cpio
або pax
. Якщо ви це зробите, вам не потрібно дзвонити cp
або zcp
додатково.
cd /path/to/source-directory
print -rN **/*(^.) **/*(.oL) | cpio -0 -p /path/to/destination-directory
Я не думаю, що є спосіб cp -r
зробити це безпосередньо. Оскільки це може бути невизначений проміжок часу, перш ніж отримати майстер find
/ awk
рішення, ось короткий сценарій Perl:
#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);
use File::Find;
use File::Basename;
die "No (valid) source directory path given.\n"
if (!$ARGV[0] || !-d -r "/$ARGV[0]");
die "No (valid) destination directory path given.\n"
if (!$ARGV[1] || !-d -w "/$ARGV[1]");
my $len = length($ARGV[0]);
my @files;
find (
sub {
my $fpath = $File::Find::name;
return if !-r -f $fpath;
push @files, [
substr($fpath, $len),
(stat($fpath))[7],
]
}, $ARGV[0]
);
foreach (sort { $a->[1] <=> $b->[1] } @files) {
if ($ARGV[2]) {
print "$_->[1] $ARGV[0]/$_->[0] -> $ARGV[1]/$_->[0]\n";
} else {
my $dest = "$ARGV[1]/$_->[0]";
my $dir = dirname($dest);
mkdir $dir if !-e $dir;
`cp -a "$ARGV[0]/$_->[0]" $dest`;
}
}
Використовуй це: ./whatever.pl /src/path /dest/path
Аргументи повинні бути обома абсолютними шляхами ; ~
або все, що оболонка розширюється до абсолютного шляху, це добре.
Якщо ви додасте третій аргумент (що завгодно, крім прямого 0
), замість копіювання він надрукує, щоб викреслити звіт про те, що він буде робити, з розмірами файлів у байтах, попередньо доданими, наприклад
4523 /src/path/file.x -> /dest/path/file.x
12124 /src/path/file.z -> /dest/path/file.z
Зауважте, вони у порядку зростання за розміром.
cp
Команда на лінії 34 є буквальною командною оболонкою, так що ви можете робити все , що ви хочете за допомогою перемикачів (я використовував , -a
щоб зберегти всі риси).
File::Find
і File::Basename
є обома основними модулями, тобто вони доступні у всіх установках perl.
cp - copy smallest files first?
але назва публікації - як copy smallest files first?
би там не було, параметри ніколи не зашкоджують моїй філософії, але все-таки ти і Давид - єдині, хто використовував, cp
і ти єдиний, хто її зняв.
cp
було те, що це найпростіший спосіб зберегти * nix характеристики файлу в (per-platform-орієнтованому) perl. Причина, яку говорить ваш рядок веб-переглядача cp -
, пов’язана з функцією SE (goofy IMO) SE, згідно з якою найпопулярніший із вибраних тегів відображається з префіксом до власного заголовка.
pearl
як виходять з дерева тут.
Іншим варіантом буде використання cp з висновком з du:
oldIFS=$IFS
IFS=''
for i in $(du -sk *mpg | sort -n | cut -f 2)
do
cp $i destination
done
IFS=$oldIFS
Це все ще можна зробити на одному рядку, але я розділив його, щоб ви могли його прочитати