가장 작은 파일을 먼저 복사하시겠습니까?

가장 작은 파일을 먼저 복사하시겠습니까?

재귀적으로 복사하려는 하위 디렉터리와 파일이 포함된 큰 디렉터리가 있습니다.

cp가장 작은 파일이 먼저 복사되도록 파일 크기 순서대로 복사 작업을 수행해야 함을 알릴 수 있는 방법이 있습니까 ?

답변1

다음은 rsync.

먼저 작은 파일만 전송하십시오.

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.

물론, 파일별 전송 순서가 가장 작은 것에서 가장 큰 것 순으로 엄격하게 정해진 것은 아니지만, 이것이 아마도 귀하의 요구 사항에 부합하는 가장 간단한 해결책일 것이라고 생각합니다.

답변2

이번에는 파일 이름 문제 없이 모든 하위 디렉터리에서 단일 스트림으로 전체 작업이 완료되었습니다. 가장 작은 파일부터 가장 큰 파일까지 모든 파일을 복사합니다. 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

또는 Giles가 디렉터리 권한 보존에 대한 답변에서 좋은 점을 지적했으므로 나도 그렇게 해야 합니다. 나는 이것이 트릭을 수행할 것이라고 생각합니다.

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

어쨌든 그것보다 더 빠르다고 확신합니다 mkdir.

답변3

직접적으로 는 아니지만 cp그것은 그 능력을 훨씬 넘어서는 것입니다. 하지만 cp올바른 순서로 파일을 호출하도록 정렬할 수 있습니다 .

Zsh를 사용하면 파일을 크기별로 편리하게 정렬할 수 있습니다.글로벌 예선. 다음은 크기가 커지는 순서대로 /path/to/source-directory파일을 아래에서 아래로 복사하는 zsh 조각입니다 /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기능. 그러나 먼저 대상 디렉터리를 만들어야 하며, 이는 신비한 oneliner에서 수행할 수 있습니다.

autoload -U zmv; alias zcp='zmv -C'
cd /path/to/source-directory
mkdir -p **/*(/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

답변4

cp -r직접적으로 할 수 있는 방법은 없는 것 같아요 . 마법 /solution 을 얻기 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

  • 매개변수는 모두 다음과 같아야 합니다.절대 경로; ~또는 쉘이 절대 경로로 확장하는 다른 모든 작업을 수행합니다.

  • 세 번째 인수(text 제외 0)를 추가하면 복사되지 않지만 파일 크기(바이트 단위)가 앞에 추가되어 수행할 작업에 대한 보고서를 stdout으로 인쇄합니다.

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

    크기가 오름차순으로 정렬되어 있으니 참고하세요.

  • 34행의 명령 은 리터럴 쉘 명령이므로 스위치를 사용하여 원하는 모든 작업을 수행할 수 있습니다( 모든 기능을 유지하기 cp위해 사용했을 뿐입니다 ).-a

  • File::Find핵심 모듈 입니다 File::Basename. 즉, 모든 Perl 설치에서 사용할 수 있습니다.

관련 정보