önce en küçük dosyalar kopyalansın mı?


15

Yinelenen kopyalamak istediğiniz alt dizinleri ve dosyaları içeren büyük bir dizin var.

cpKopyalama işlemini dosya boyutuna göre yapması gerektiğini söylemenin herhangi bir yolu var mı , böylece en küçük dosyalar önce kopyalanıyor mu?


1
Sadece bir XY probleminin olmadığından emin olmak için , bunu neden yapmak istediğinizi açıklayabilir misiniz?
goldilocks

4
@ TAFKA'goldilocks '- Çok sayıda video dosyam var ve her dizinin kalitesini test etmek istiyorum. En küçük video, dosyaların geri kalanının da kötü olup olmadığını hızlı bir şekilde gösterecektir.
nbubis

Yanıtlar:


10

Bu, tüm işi tek seferde yapar - tüm alt dizinlerde, dosya adı sorunları olmadan tek bir akışta. Sahip olduğunuz her dosyayı en küçükten en büyüğe kopyalar. Henüz mkdir ${DESTINATION}mevcut değilse yapmanız gerekir .

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 -

Ne var biliyor musun? Bunun yapmadığı şey boş alt dizinlerdir. Bu boru hattı üzerinden biraz yeniden yönlendirme yapabilirdim, ama bu sadece gerçekleşmeyi bekleyen bir yarış durumu. En basit olanı muhtemelen en iyisidir. Bunu daha sonra yapın:

find . -type d -printf 'mkdir -p "'"${DESTINATION}"'/%p"\n' |
    . /dev/stdin

Veya Gilles, dizin izinlerini korumak için cevabında çok iyi bir noktaya değindiğinden, denemeliyim. Bunun yapacağını düşünüyorum:

find . -type d -printf '[ -d "'"${DESTINATION}"'/%p" ] || 
    cp "%p" -t "'"${DESTINATION}"'"\n' |
. /dev/stdin

Bahse girerim ki bu mkdirzaten her zamankinden daha hızlı .


1
Lanet olsun, mikeserv! +1
goldilocks

3
@ TAFKA'goldilocks 'Bunu iltifat olarak kabul edeceğim. Çok teşekkürler.
mikeserv

15

İşte hızlı ve kirli bir yöntem kullanarak rsync. Bu örnek için 10 MB altındaki herhangi bir şeyin "küçük" olduğunu düşünüyorum.

İlk önce sadece küçük dosyaları aktarın:

rsync -a --max-size=10m srcdir dstdir

Ardından kalan dosyaları aktarın. Önceden aktarılan küçük dosyalar değiştirilmedikçe yeniden kopyalanmaz.

rsync -a srcdir dstdir

itibaren 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  doesnt
          affect  the  data  that  goes  into  the file-lists, and thus it
          doesnt 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.

Tabii ki, dosya-dosya aktarım sırası kesinlikle en küçükten en büyüğe değil, ama ihtiyaçlarınızın ruhunu karşılayan en basit çözüm olabileceğini düşünüyorum.


Burada 2 adet sabit bağlantı ve yumuşak bağlantı elde edersiniz ve her biri iki kopya için gerçek dosyalara dönüştürülür. --copy-dest=DIRVe / veya --compare-dest=DIRbence çok daha iyi yapardın . Sadece cevabımı --hard-dereferencegönderdikten tarsonra kendi cevabımı gönderdikten sonra kendimi eklemek zorunda olduğumu biliyorum . Ben rsyncaslında başkaları ile yerel dosya sistemlerine daha spesifik davranıyor düşünüyorum - USB anahtarları ile kullanırdım ve bir bant genişliği sınırı belirlemezseniz otobüs sel olurdu. Sanırım bu ikisinden birini kullanmalıydım.
mikeserv

1
"Hızlı ve kirli yöntem" için +1. Daha basit, en azından otomasyon amaçları ve gelecekteki bakım için daha iyidir. Bence bu aslında oldukça temiz. "Zarif" ve "kludgy" ve "sağlam" ve "kararsız" bazen tasarım hedefleri olarak çelişebilir, ancak vurulabilecek iyi bir denge vardır ve bence bu zarif ve oldukça sağlamdır.
Wildcard

4

cpDoğrudan değil , bu yeteneklerinin çok ötesinde. Ancak cp, dosyaları doğru sırayla çağırmayı düzenleyebilirsiniz .

Zsh, glob niteleyici ile dosyaları boyuta göre sıralamaya izin verir . İşte hangi kopyalar altından boyutu artan sırada dosyaları zsh snippet'ine /path/to/source-directoryaltındakiler için /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

Bir döngü yerine, zcpişlevi kullanabilirsiniz . Ancak önce şifreli bir satırda yapılabilecek hedef dizinleri oluşturmanız gerekir.

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'

Bu, kaynak dizinlerin sahipliğini korumaz. İsterseniz, cpioveya gibi uygun bir kopyalama programına kaydolmanız gerekir pax. Bunu yaparsanız, aramanıza cpveya zcpek olarak aramanıza gerek yoktur .

cd /path/to/source-directory
print -rN **/*(^.) **/*(.oL) | cpio -0 -p /path/to/destination-directory

2

Bunu cp -rdoğrudan yapmanın bir yolu olduğunu sanmıyorum . Bir sihirbaz find/ awkçözüm bulmadan önce belirsiz bir süre olabileceğinden , işte hızlı bir perl betiği:

#!/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`;
    }
} 
  • Bunu kullan: ./whatever.pl /src/path /dest/path

  • Argümanların her ikisi de mutlak yol olmalıdır ; ~veya kabuğun mutlak bir yola genişlettiği herhangi bir şey iyidir.

  • Üçüncü bir argüman eklerseniz (değişmez bir şey dışında herhangi bir şey 0), kopyalamak yerine, ne yapacağının bir raporunu standart olarak yazdırır;

    4523 /src/path/file.x -> /dest/path/file.x
    12124 /src/path/file.z -> /dest/path/file.z

    Bunların boyuta göre artan sırada olduğuna dikkat edin.

  • cpEğer anahtarlar (Sadece kullanılan ile istediğinizi yapabilirsiniz, böylece hat 34 üzerinde komut, bir hazır kabuk komut -atüm özelliklerini korumak için).

  • File::Findve File::Basenameher ikisi de çekirdek modüllerdir, yani perl'in tüm kurulumlarında kullanılabilirler.


tartışmasız, buradaki tek doğru cevap budur. Yoksa başlık ... sadece değişti ...? Tarayıcı pencerem çağrıldı, cp - copy smallest files first?ancak yazının başlığı copy smallest files first?Her neyse, seçenekler asla zarar görmedi benim felsefem, ama yine de, sen ve David kullanılan cptek sensin ve onu çeken tek kişisin.
mikeserv

@mikeserv Kullanmamın tek nedeni cp, (çapraz platform odaklı) perl'de * nix dosya özelliklerini korumanın en basit yoluydu. Tarayıcı çubuğunuzun söylemesinin cp - nedeni, seçilen etiketlerin en popüler öğelerinin gerçek başlığın önüne eklenmiş olduğu (IMO goofy) SE özelliğinden kaynaklanmaktadır.
goldilocks

Tamam, iltifatımı geri çekiyorum. Pek değil, sık sık pearlburadaki ağaç işlerinden çıktığını görmüyorsunuz .
mikeserv

1

başka bir seçenek du çıktı ile cp kullanmak olacaktır:

oldIFS=$IFS
IFS=''
for i in $(du -sk *mpg | sort -n | cut -f 2)
do
    cp $i destination
done
IFS=$oldIFS

Bu yine de tek bir satırda yapılabilir, ama okuyabilmeniz için bölüyorum


En azından $ IFS hakkında bir şey yapmanıza gerek yok mu?
mikeserv

Evet ... Dosya adlarında hiç kimsenin yeni satır olmadığını varsaymaya devam ediyorum
David Wilkins

1
Bu aynı zamanda OP'nin açıklanan dizin hiyerarşisinde özyinelemeyi ele almıyor gibi görünüyor.
cpugeniusmv

1
@cpugeniusmv Doğru ... Özyinelemeli kısmı bir şekilde özledim .... Özyineleme işlemek için bunu değiştirebilirim, ama bu noktada diğer cevapların daha iyi bir iş yaptığını düşünüyorum. Soruyu gören birine yardımcı olması için bunu burada bırakacağım.
David Wilkins

1
@DavidWilkins - bu çok yardımcı olur.
nbubis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.