Mam duży katalog zawierający podkatalogi i pliki, które chcę kopiować rekurencyjnie.
Czy jest jakiś sposób, aby powiedzieć cp
, że powinien wykonać operację kopiowania w kolejności wielkości pliku, aby najpierw skopiować najmniejsze pliki?
Mam duży katalog zawierający podkatalogi i pliki, które chcę kopiować rekurencyjnie.
Czy jest jakiś sposób, aby powiedzieć cp
, że powinien wykonać operację kopiowania w kolejności wielkości pliku, aby najpierw skopiować najmniejsze pliki?
Odpowiedzi:
Wykonuje to całą pracę za jednym razem - we wszystkich katalogach potomnych, wszystko w jednym strumieniu bez problemów z nazwami plików. Skopiuje od najmniejszego do największego każdego pliku, który masz. Będziesz musiał, mkdir ${DESTINATION}
jeśli jeszcze nie istnieje.
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 -
Ale wiesz co? Nie robi to pustych katalogów potomnych. Mógłbym dokonać przekierowania przez ten rurociąg, ale to tylko warunek wyścigu, który czeka na to, aby się wydarzyć. Najprostszy jest prawdopodobnie najlepszy. Po prostu zrób to później:
find . -type d -printf 'mkdir -p "'"${DESTINATION}"'/%p"\n' |
. /dev/stdin
Lub, ponieważ Gilles ma bardzo dobry punkt w swojej odpowiedzi, aby zachować uprawnienia do katalogu, powinienem również spróbować. Myślę, że to zrobi:
find . -type d -printf '[ -d "'"${DESTINATION}"'/%p" ] ||
cp "%p" -t "'"${DESTINATION}"'"\n' |
. /dev/stdin
Byłbym skłonny założyć się, że to szybciej niż mkdir
tak.
Oto szybka i brudna metoda rsync
. W tym przykładzie uważam, że wszystko poniżej 10 MB jest „małe”.
Najpierw przenieś tylko małe pliki:
rsync -a --max-size=10m srcdir dstdir
Następnie przenieś pozostałe pliki. Przeniesione wcześniej małe pliki nie zostaną ponownie skopiowane, chyba że zostaną zmodyfikowane.
rsync -a srcdir dstdir
Od 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.
Oczywiście kolejność przesyłania plików po pliku nie jest ściśle od najmniejszej do największej, ale myślę, że może to być najprostsze rozwiązanie, które spełnia ducha Twoich wymagań.
--copy-dest=DIR
i / lub --compare-dest=DIR
myślę. Wiem tylko, bo musiałem dodać --hard-dereference
się do tar
po zaksięgowaniu własną odpowiedź, ponieważ brakowało mi linki. Wydaje mi się, że i rsync
tak zachowuje się bardziej specyficznie dla lokalnych systemów plików z tymi innymi - użyłem go z kluczami USB i zalałoby to magistralę, chyba że ustawię limit przepustowości. Myślę, że powinienem był użyć jednego z tych innych.
Nie cp
bezpośrednio, to znacznie przekracza jego możliwości. Ale możesz ustawić wywoływanie cp
plików we właściwej kolejności.
Zsh wygodnie umożliwia sortowanie plików według rozmiaru za pomocą kwalifikatora glob . Oto fragment kodu zsh, który kopiuje pliki w kolejności rosnącej od dolnej /path/to/source-directory
do dolnej /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
Zamiast pętli możesz użyć zcp
funkcji. Najpierw jednak musisz utworzyć katalog docelowy, co można zrobić w tajemniczym oneliner.
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'
To nie chroni własności katalogów źródłowych. Jeśli chcesz, musisz zapisać odpowiedni program do kopiowania, taki jak cpio
lub pax
. Jeśli to zrobisz, nie musisz dzwonić cp
ani zcp
dodatkowo.
cd /path/to/source-directory
print -rN **/*(^.) **/*(.oL) | cpio -0 -p /path/to/destination-directory
Nie wydaje mi się, żeby można to cp -r
zrobić bezpośrednio. Ponieważ może upłynąć nieokreślony czas, zanim pojawi się kreator find
/ awk
rozwiązanie, oto krótki skrypt w perlu:
#!/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`;
}
}
Użyj tego: ./whatever.pl /src/path /dest/path
Argumenty powinny być ścieżkami bezwzględnymi ; ~
lub cokolwiek innego, co powłoka rozwija na ścieżkę absolutną, jest w porządku.
Jeśli dodasz trzeci argument (cokolwiek, z wyjątkiem literału 0
), zamiast go skopiować, wydrukuje standardowy raport o tym, co by zrobił, z rozmiarami plików w bajtach, np.
4523 /src/path/file.x -> /dest/path/file.x
12124 /src/path/file.z -> /dest/path/file.z
Zauważ, że są w porządku rosnącym według rozmiaru.
cp
Komenda na linii 34 jest poleceniem powłoki dosłowne, więc możesz robić, co chcesz z przełączników (tylko używane -a
, aby zachować wszystkie cechy).
File::Find
i File::Basename
oba są modułami podstawowymi, tzn. są dostępne we wszystkich instalacjach Perla.
cp - copy smallest files first?
ale tytuł postu jest po prostu. W copy smallest files first?
każdym razie opcje nigdy nie zaszkodzą mojej filozofii, ale ty i David jesteście jedynymi, którzy skorzystali, cp
a ty jesteś jedynym, który to zrobił.
cp
było to, że jest to najprostszy sposób na zachowanie właściwości pliku * nix w perlu (zorientowanym na wiele platform). Powodem, dla którego wyświetla się pasek przeglądarki, cp -
jest funkcja SE (niemądra), w wyniku której najpopularniejszy z wybranych tagów pojawia się przed rzeczywistym tytułem.
pearl
jak wychodzi z tutejszej stolarki.
inną opcją byłoby użycie cp z wyjściem du:
oldIFS=$IFS
IFS=''
for i in $(du -sk *mpg | sort -n | cut -f 2)
do
cp $i destination
done
IFS=$oldIFS
Można to nadal zrobić w jednym wierszu, ale podzieliłem go, abyś mógł go przeczytać