У мене є великий каталог, що містить підкаталоги та файли, які я хочу копіювати рекурсивно.
Чи є спосіб сказати, 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
Це все ще можна зробити на одному рядку, але я розділив його, щоб ви могли його прочитати