คัดลอกไฟล์ที่เล็กที่สุดก่อน?


15

ฉันมีไดเรกทอรีขนาดใหญ่ที่มีไดเรกทอรีย่อยและไฟล์ที่ฉันต้องการคัดลอกซ้ำ

มีวิธีใดบ้างที่จะบอกcpว่าควรทำการคัดลอกตามขนาดไฟล์เพื่อให้ไฟล์ที่เล็กที่สุดถูกคัดลอกก่อน?


1
เพียงเพื่อให้แน่ใจว่าไม่มีปัญหาเกี่ยวกับXYคุณสามารถอธิบายได้ว่าทำไมคุณถึงต้องการทำเช่นนี้?
goldilocks

4
@ TAFKA'goldilocks '- ฉันมีไฟล์วิดีโอจำนวนมากและฉันต้องการทดสอบคุณภาพแต่ละไดเรกทอรี วิดีโอขนาดเล็กที่สุดจะบอกฉันอย่างรวดเร็วว่าไฟล์ที่เหลือนั้นไม่ดีเช่นกัน
nbubis

คำตอบ:


10

นี่เป็นการทำงานทั้งหมดในครั้งเดียว - ในไดเรกทอรีลูกทั้งหมดทั้งหมดในสตรีมเดียวโดยไม่มีปัญหาชื่อไฟล์ มันจะคัดลอกจากที่เล็กที่สุดไปหามากที่สุดทุกไฟล์ที่คุณมี คุณจะต้อง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

หรือเนื่องจาก Gilles เป็นจุดที่ดีมากในคำตอบของเขาในการสงวนสิทธิ์ไดเรกทอรีฉันควรลองด้วย ฉันคิดว่ามันจะทำ:

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

ฉันยินดีที่จะเดิมพันที่เร็วกว่าmkdirเดิม


1
เจ้า mikeserv! +1
goldilocks

3
@ TAFKA'goldilocks 'ฉันจะใช้มันเป็นคำชม ขอบคุณมาก ๆ.
mikeserv

15

นี่เป็นวิธีที่รวดเร็วและสกปรกโดยใช้ rsyncนี่คือวิธีการที่รวดเร็วและสกปรกใช้สำหรับตัวอย่างนี้ฉันกำลังพิจารณาอะไรที่ต่ำกว่า 10 MB ให้เป็น "เล็ก"

เริ่มแรกถ่ายโอนไฟล์ขนาดเล็ก:

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  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.

แน่นอนลำดับของการถ่ายโอนไฟล์ต่อไฟล์ไม่ได้เล็กที่สุดไปหามากที่สุด แต่ฉันคิดว่ามันอาจเป็นทางออกที่ง่ายที่สุดที่ตรงกับความต้องการของคุณ


ที่นี่คุณจะได้รับฮาร์ดลิงก์และซอฟต์ลิงค์ 2 ชุดจะถูกแปลงเป็นไฟล์จริงสำหรับแต่ละสำเนาสองชุด คุณจะทำได้ดีขึ้นด้วย--copy-dest=DIRและ / หรือ--compare-dest=DIRฉันคิดว่า ฉันรู้เพียงแค่สาเหตุที่ฉันต้องเพิ่ม--hard-dereferenceตัวเองtarหลังจากโพสต์คำตอบของตัวเองเพราะฉันหายไปเชื่อมโยง ฉันคิดว่าrsyncจริง ๆ แล้วจะทำงานเฉพาะกับระบบไฟล์ในท้องถิ่นกับคนอื่น ๆ ต่อไป - ฉันเคยใช้มันกับปุ่ม USB และมันจะท่วมบัสถ้าฉันตั้งค่าขีด จำกัด แบนด์วิดท์ ฉันคิดว่าฉันควรใช้อย่างใดอย่างหนึ่งเหล่านั้นแทน
mikeserv

1
+1 สำหรับ "วิธีที่รวดเร็วและสกปรก" เรียบง่ายมักจะดีกว่าอย่างน้อยสำหรับวัตถุประสงค์อัตโนมัติและการบำรุงรักษาในอนาคต ฉันคิดว่ามันสะอาดจริง ๆ "Elegant" vs "kludgy" และ "strong" vs "unstable" อาจขัดแย้งกับเป้าหมายการออกแบบ แต่มีความสมดุลที่ดีที่สามารถทำให้เกิดขึ้นได้และฉันคิดว่านี่เป็นสิ่งที่สวยงามและแข็งแกร่ง
Wildcard

4

ไม่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ฟังก์ชัน อย่างไรก็ตามคุณต้องสร้างไดเรกทอรีปลายทางก่อนซึ่งสามารถทำได้ใน cryptic 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'

สิ่งนี้ไม่รักษาความเป็นเจ้าของไดเรกทอรีต้นทาง หากคุณต้องการที่คุณจะต้องสมัครเข้าโปรแกรมคัดลอกที่เหมาะสมเช่นหรือcpio paxหากคุณทำเช่นนั้นคุณไม่จำเป็นต้องโทรcpหรือทำอะไรzcpนอกจากนี้

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

2

ฉันไม่คิดว่าจะมีวิธีใดที่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และคุณเป็นคนเดียวที่ดึงมันออกมา
mikeserv

@mikeserv เหตุผลเดียวที่ฉันใช้cpเพราะมันเป็นวิธีที่ง่ายที่สุดในการรักษาลักษณะไฟล์ * nix ใน perl (ข้ามแพลตฟอร์ม) เหตุผลที่แถบเบราว์เซอร์ของคุณบอกว่าcp - เป็นเพราะคุณสมบัติ SE (IMO goofy) SE โดยที่แท็กที่ได้รับความนิยมสูงสุดจะปรากฏขึ้นนำหน้าชื่อจริง
goldilocks

ตกลงแล้วฉันก็ถอนคำชมของฉัน ไม่จริงๆคุณไม่เห็นการpearlออกมาจากงานไม้แถวนี้บ่อยนัก
mikeserv

1

ตัวเลือกอื่นจะใช้ cp กับผลลัพธ์จาก du:

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

สิ่งนี้สามารถทำได้ในหนึ่งบรรทัด แต่ฉันแยกมันเพื่อให้คุณสามารถอ่านได้


อย่างน้อยคุณไม่จำเป็นต้องทำบางสิ่งเกี่ยวกับ $ IFS หรือ
mikeserv

ใช่ ... ฉันสมมติว่าไม่มีใครมีบรรทัดใหม่ในชื่อไฟล์ของพวกเขา
David Wilkins

1
สิ่งนี้ดูเหมือนจะไม่จัดการการเรียกซ้ำผ่านลำดับชั้นไดเรกทอรีที่ OP อธิบาย
cpugeniusmv

1
@cpugeniusmv ถูกต้อง ... ฉันพลาดส่วนที่เรียกซ้ำ .... ฉันสามารถแก้ไขสิ่งนี้เพื่อจัดการการเรียกซ้ำ แต่ฉันคิดว่า ณ จุดนี้คำตอบอื่น ๆ จะทำงานได้ดีขึ้น ฉันจะออกจากที่นี่ในกรณีที่ช่วยคนที่เห็นคำถาม
David Wilkins

1
@DavidWilkins - มันช่วยได้มาก
nbubis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.