Tôi có một thư mục lớn chứa các thư mục con và tệp mà tôi muốn sao chép đệ quy.
Có cách nào để nói cp
rằng nó nên thực hiện thao tác sao chép theo thứ tự kích thước tệp, để các tệp nhỏ nhất được sao chép trước không?
Tôi có một thư mục lớn chứa các thư mục con và tệp mà tôi muốn sao chép đệ quy.
Có cách nào để nói cp
rằng nó nên thực hiện thao tác sao chép theo thứ tự kích thước tệp, để các tệp nhỏ nhất được sao chép trước không?
Câu trả lời:
Điều này thực hiện toàn bộ công việc trong một lần - trong tất cả các thư mục con, tất cả trong một luồng mà không có bất kỳ vấn đề nào về tên tệp. Nó sẽ sao chép từ nhỏ nhất đến lớn nhất mỗi tệp bạn có. Bạn sẽ cần mkdir ${DESTINATION}
nếu nó không tồn tại.
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 -
Bạn biết những gì, mặc dù? Điều này không làm là thư mục con trống . Tôi có thể thực hiện một số chuyển hướng trên đường ống đó, nhưng đó chỉ là một điều kiện cuộc đua đang chờ xảy ra. Đơn giản nhất có lẽ là tốt nhất. Vì vậy, chỉ cần làm điều này sau đó:
find . -type d -printf 'mkdir -p "'"${DESTINATION}"'/%p"\n' |
. /dev/stdin
Hoặc, vì Gilles đã đưa ra một điểm rất tốt trong câu trả lời của mình để bảo vệ các quyền của thư mục, tôi cũng nên thử. Tôi nghĩ rằng điều này sẽ làm điều đó:
find . -type d -printf '[ -d "'"${DESTINATION}"'/%p" ] ||
cp "%p" -t "'"${DESTINATION}"'"\n' |
. /dev/stdin
Tôi sẵn sàng đặt cược nhanh hơn mkdir
dù sao đi nữa.
Đây là một phương pháp nhanh chóng và bẩn bằng cách sử dụng rsync
. Trong ví dụ này, tôi đang xem mọi thứ dưới 10 MB là "nhỏ".
Đầu tiên chỉ chuyển các tệp nhỏ:
rsync -a --max-size=10m srcdir dstdir
Sau đó chuyển các tập tin còn lại. Các tệp nhỏ được chuyển trước đó sẽ không được sao chép lại trừ khi chúng được sửa đổi.
rsync -a srcdir dstdir
Từ 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.
Tất nhiên, thứ tự chuyển từng tập tin không hoàn toàn nhỏ nhất đến lớn nhất, nhưng tôi nghĩ đó có thể là giải pháp đơn giản nhất đáp ứng tinh thần yêu cầu của bạn.
--copy-dest=DIR
và / hoặc --compare-dest=DIR
tôi nghĩ. Tôi chỉ biết nguyên nhân tôi phải tự thêm --hard-dereference
vào tar
sau khi đăng câu trả lời của riêng mình vì tôi đã bỏ lỡ các liên kết. Tôi nghĩ rằng rsync
thực sự hành xử cụ thể hơn đối với các hệ thống tệp cục bộ với những hệ thống khác dù sao - tôi đã từng sử dụng nó với các phím USB và nó sẽ tràn ngập xe buýt trừ khi tôi đặt giới hạn băng thông. Tôi nghĩ rằng tôi nên sử dụng một trong những người khác thay thế.
Không cp
trực tiếp, điều đó vượt quá khả năng của nó. Nhưng bạn có thể sắp xếp để gọi cp
các tập tin theo đúng thứ tự.
Zsh thuận tiện cho phép sắp xếp các tệp theo kích thước với vòng loại toàn cầu . Đây là đoạn mã zsh sao chép các tệp theo thứ tự tăng kích thước từ dưới /path/to/source-directory
lên dưới /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
Thay vì một vòng lặp, bạn có thể sử dụng zcp
chức năng. Tuy nhiên, bạn cần tạo các thư mục đích trước, có thể được thực hiện trong một oneliner khó hiểu.
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'
Điều này không bảo vệ quyền sở hữu của các thư mục nguồn. Nếu bạn muốn điều đó, bạn sẽ cần tranh thủ một chương trình sao chép phù hợp như cpio
hoặc pax
. Nếu bạn làm điều đó, bạn không cần phải gọi cp
hoặc zcp
ngoài ra.
cd /path/to/source-directory
print -rN **/*(^.) **/*(.oL) | cpio -0 -p /path/to/destination-directory
Tôi không nghĩ có cách nào cp -r
để làm điều này trực tiếp. Vì đó có thể là một khoảng thời gian không xác định trước khi bạn nhận được một giải pháp find
/ thuật sĩ awk
, đây là tập lệnh perl nhanh:
#!/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`;
}
}
Dùng cái này: ./whatever.pl /src/path /dest/path
Các đối số nên là cả hai đường dẫn tuyệt đối ; ~
hoặc bất cứ điều gì khác mà vỏ mở rộng đến một đường dẫn tuyệt đối là tốt.
Nếu bạn thêm một đối số thứ ba (bất cứ điều gì, ngoại trừ bằng chữ 0
), thay vì sao chép, nó sẽ in ra để báo cáo chuẩn về những gì nó sẽ làm, với kích thước tệp được tính theo byte, ví dụ:
4523 /src/path/file.x -> /dest/path/file.x
12124 /src/path/file.z -> /dest/path/file.z
Lưu ý rằng đây là theo thứ tự tăng dần theo kích thước.
Các cp
lệnh trên dòng 34 là một lệnh shell đen, vì vậy bạn có thể làm bất cứ điều gì bạn muốn với thiết bị chuyển mạch (Tôi chỉ được sử dụng -a
để bảo vệ tất cả những đặc điểm).
File::Find
và File::Basename
là cả hai mô-đun cốt lõi, tức là chúng có sẵn trong tất cả các cài đặt của perl.
cp - copy smallest files first?
nhưng tiêu đề của bài viết chỉ là copy smallest files first?
Dù sao, các tùy chọn không bao giờ bị tổn thương là triết lý của tôi, nhưng vẫn vậy, bạn và David là những người duy nhất đã sử dụng cp
và bạn là người duy nhất rút nó ra.
cp
là vì đó là cách đơn giản nhất để bảo tồn các đặc điểm tệp * nix trong perl (định hướng đa nền tảng). Lý do thanh trình duyệt của bạn nói cp -
là vì tính năng SE (ngu ngốc IMO), theo đó, các thẻ phổ biến nhất được chọn xuất hiện trước tiêu đề thực tế.
pearl
ra khỏi đồ gỗ quanh đây.
một tùy chọn khác là sử dụng cp với đầu ra từ du:
oldIFS=$IFS
IFS=''
for i in $(du -sk *mpg | sort -n | cut -f 2)
do
cp $i destination
done
IFS=$oldIFS
Điều này vẫn có thể được thực hiện trên một dòng, nhưng tôi chia nó để bạn có thể đọc nó