재귀적으로 복사하려는 하위 디렉터리와 파일이 포함된 큰 디렉터리가 있습니다.
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 설치에서 사용할 수 있습니다.