재귀 적으로 복사하려는 하위 디렉토리와 파일을 포함하는 큰 디렉토리가 있습니다.
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
또는 Gilles는 디렉토리 권한을 보존하기 위해 그의 대답에서 매우 좋은 지적을하기 때문에 시도해야합니다. 나는 이것이 그렇게 할 것이라고 생각한다.
find . -type d -printf '[ -d "'"${DESTINATION}"'/%p" ] ||
    cp "%p" -t "'"${DESTINATION}"'"\n' |
. /dev/stdin
mkdir어쨌든 보다 더 빨리 기꺼이 내기를 할 것 입니다.
답변
사용하는 빠르고 더러운 방법은 다음과 같습니다 rsync. 이 예제에서는 10MB 미만의 것을 “작은”것으로 간주합니다.
먼저 작은 파일 만 전송하십시오.
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.
물론 파일 별 전송 순서는 최소에서 최대로 엄격하지는 않지만 요구 사항의 정신을 충족시키는 가장 간단한 솔루션 일 수 있습니다.
답변
아니 cp직접, 그 잘 자사의 능력을 넘어. 그러나 cp올바른 순서로 파일 을 호출하도록 정렬 할 수 있습니다 .
Zsh를 사용하면 glob 한정자를 사용하여 파일을 크기별로 정렬 할 수 있습니다 . 아래에서 아래 /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 **/*(/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솔루션 을 얻기까지는 시간이 불확실 할 수 있으므로 다음과 같은 간단한 펄 스크립트가 있습니다 :
#!/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크기별로 오름차순으로 표시됩니다.
 - 
cp34 행 의 명령은 문자 그대로의 쉘 명령이므로 스위치로 원하는 모든 작업을 수행 할 수 있습니다 (방금-a모든 특성을 유지하는 데 사용 했습니다). - 
File::Find그리고File::Basename, 두 핵심 모듈이다 그들은 펄의 모든 설치에서 사용할 수 있습니다 즉. 
답변
또 다른 옵션은 du의 출력에 cp를 사용하는 것입니다.
oldIFS=$IFS
IFS=''
for i in $(du -sk *mpg | sort -n | cut -f 2)
do
    cp $i destination
done
IFS=$oldIFS
이것은 여전히 한 줄로 할 수는 있지만 읽을 수 있도록 분할했습니다.