rsync gần đây nhất x GB


8

Tôi đang tìm kiếm một lệnh / tập lệnh để cho phép các tệp được sửa đổi gần đây nhất (tối đa) 10GB được sao chép sang một máy tính khác.

Vì vậy, nếu có 4 tệp 4 GB mỗi tệp, chỉ có 2 tệp trong số đó được chuyển theo tập lệnh, Nếu có 12 tệp lớn 1 GB, chỉ nên chuyển 10 tệp gần đây nhất.


1
Tôi không thể nghĩ ra cách nào để làm điều này, nhưng để làm rõ câu hỏi của bạn, bạn có thực sự muốn 10GB tệp được sửa đổi gần đây nhất hoặc bất kỳ tập hợp nào lên tới 10GB tệp không? Tôi không tin có bất kỳ cách nào để buộc rsync ưu tiên cho các tệp gần đây nhất. Câu trả lời gần nhất tôi có thể nghĩ đến là hạn chế băng thông đến một giá trị đã biết (như 1MB / giây) và giết rsync sau khi đủ thời gian để chuyển x GB dữ liệu. Không hoàn hảo vì ràng buộc băng thông là một giá trị tối đa, do đó bạn không thể chuyển nhiều như bạn muốn.
Johnny

gần đây nhất. bởi tập tin mtime
exussum

Câu trả lời:


6

Đây là một kịch bản mà chỉ những gì bạn yêu cầu.

Các yêu cầu

  • Các tập tin được truyền phải có tổng kích thước nhỏ hơn một ngưỡng.
  • Các tập tin phải được sửa đổi so với đích rsync.
  • Nếu không phải tất cả các tệp có thể được chuyển, chỉ những tệp được sửa đổi gần đây nhất phải được chọn.

Các chi tiết

Nó sử dụng rsync --dry-runđể xây dựng một danh sách các tệp sẽ được chuyển (đây là các tệp đã được sửa đổi). Sau đó, nó sử dụng kết hợp dulsđể có được kích thước tệp và mtime. Sau đó, nó sắp xếp các tệp theo mtime và sau đó lặp lại chúng cho đến khi tổng kích thước vượt quá ngưỡng. Cuối cùng, nó gọi rsync một lần nữa chỉ với các tệp được sửa đổi gần đây nhất và tổng kích thước dưới ngưỡng.

Kịch bản hơi xấu, nhưng nó hoạt động. Một hạn chế lớn là nó phải được thực thi trên máy có chứa rsync từ thư mục. Nó có thể được sửa đổi để sử dụng ssh để sử dụng một thư mục từ xa, nhưng kích thước đó được để lại cho người đọc.

Cuối cùng, các rsynctùy chọn được mã hóa cứng vào tập lệnh, nhưng đây là một thay đổi dễ dàng nếu bạn muốn chỉ định chúng trên dòng lệnh. Ngoài ra, toán để tính kích thước được thực hiện theo byte. Điều này có thể được thay đổi thành kilo / mega / gigabyte bằng cách sửa đổi cuộc gọi thành du và giảm ngưỡng theo cùng một yếu tố.

Sử dụng

./rsyncrecent.sh rsync-from-directory rsync-to-directory

trong đó rsync-from-directorylà một thư mục cục bộ và rsync-to-directorylà bất kỳ thư mục địa phương hoặc từ xa. Các tùy chọn mặc định được mã hóa cứng -avzvà ngưỡng mặc định được mã hóa cứng là 10GiB.

Kịch bản

#!/bin/bash

RSYNC=rsync
RSYNC_OPTS=-avz
THRESHOLD=10737418240

usage () {
  echo >&2 "Usage:  $0 from-location to-location"
  exit 1
}

[ "$#" -eq 2 ] || usage

RSYNC_FROM=$1
RSYNC_TO=$2

echo "Fetching file list for $RSYNC $RSYNC_OPTS $RSYNC_FROM $RSYNC_TO"

# get list of changed files
FILES=`$RSYNC $RSYNC_OPTS --dry-run  $RSYNC_FROM $RSYNC_TO | sed -n '/list$/,/^$/{/sending.*list$/ d ; /^$/ d ; /\/$/ d ;; p}'`

# reported files are relative to ..RSYNC_FROM, so rather than transforming filenames, lets just move there
pushd $RSYNC_FROM > /dev/null

# get modified time and sizes for all files
i=0
for FILE in $FILES
do
   #strip first part of path so files are relative to RSYNC_FROM
   FILE=${FILE#*/}
   #FSIZE=`ls -l $FILE | cut -f5 -d' '`
   FSIZE=`du -bs $FILE`
   FMTIME=`ls -l --time-style=+%s $FILE | cut -f6 -d' '`
   FLIST[$i]=`echo $FMTIME $FILE $FSIZE`
   ((i=$i+1))
done

# go back to original directory
popd > /dev/null

# sort list according to modified time
IFS=$'\n' FLIST=($(sort -rg <<<"${FLIST[*]}"))

max=$i
i=0
size=0
#NEWFLIST=''

# add up the files in mtime order until threshold is reached
for ((i=0; i<$max; i++))
do
   s=`echo ${FLIST[$i]} | cut -f3 -d' '`
   f=`echo ${FLIST[$i]} | cut -f2 -d' '`
   ((size=$size+$s))
   if (( "$size" > "$THRESHOLD" ))
   then
      break
   fi
   NEWFLIST="$NEWFLIST $f"
   echo $f >> /tmp/rsyncfilelist
done

$RSYNC $RSYNC_OPTS --dry-run $RSYNC_FROM --files-from=/tmp/rsyncfilelist  $RSYNC_TO

rm /tmp/rsyncfilelist

Hoạt động rất tốt, Một lần nó không hoạt động là khi có một tệp lớn hơn 10GB là tệp gần đây nhất
exussum

Nếu bạn luôn muốn tệp đầu tiên chuyển bất kể ngưỡng nào, trong vòng lặp cuối cùng bên trong if (( "$size" > "$THRESHOLD" ))điều kiện, hãy thêm một kiểm tra (trước break) cho i==0và nếu vậy , echo $f >> /tmp/rsyncfilelist.
casey

1

Tôi sẽ sử dụng rsync "--dry-run" (hoặc "-n") để lấy danh sách các tệp mới hơn. Sau đó, tôi sẽ sử dụng một rsync khác với tùy chọn "--files-from = -" để gửi các tệp. Ở giữa có perl "xấu xí" .
Một cái gì đó như thế này:

#!/usr/bin/perl

$source="/somedir";
$target="host:/remotedir";
$maxsize=10*1024**3; # 10GB 

open (RSOUT,"|rsync -av --files-from=- $source $target");
open (RSIN, "rsync -avn $source $target |");
while (<RSIN>)
{
        chomp;
        last if (/^$/);
        if (-f "$_")
        {
                next if ($size + -s "$_" > $maxsize);
                $size += -s "$_";
                printf RSOUT "%s\n", $_;
        }
}

Lưu ý tôi đã không kiểm tra với hơn 10 GB, có thể perl sẽ tràn ở một số giới hạn; để giải quyết điều đó, thay vì đếm byte, hãy sử dụng Kbytes:

$maxsize=10*1024**2; # 10M of Kbytes
...
     $size +=( -s "$_")/1024;

EDIT: Tôi lưu ý rằng giải pháp đầu tiên này sẽ không sắp xếp tệp theo mtime , đây là một giải pháp hoàn chỉnh hơn (tương tự như tập lệnh bash đã được đăng bởi người khác).

#!/usr/bin/perl
use File::stat;

$source="/somedir/";
$target="host:/remotedir";
$maxsize=10 * 1024**3; # 10GB  

open (RSOUT,"|rsync -av --files-from=- $source $target");
open (RSIN, "rsync -avn $source $target |");
while (<RSIN>)
{
    chomp;
    last if (/^$/);
    if (-f "$_")
    {
            my $fileattr;
            my $stat=stat($_);
            $fileattr->{name}=$_;
            $fileattr->{size}=$stat->size;
            $hash{sprintf ("%s %s\n", $stat->mtime, $_)}=$fileattr;
    }

}

foreach $key (reverse sort keys %hash)
{
    next if ( ($size + $hash{$key}->{size}) > $maxsize);
    $size += $hash{$key}->{size};
    print RSOUT $hash{$key}->{name}, "\n";
}

0

Bạn có thể phân tích đầu ra được sắp xếp của du. Giả sử các tiện ích GNU:

du -0ak | sort -z -k1n | awk -v 'RS=\0' -v 'ORS=\0' '
    (size += $1) > 10*1024*1024 {quit}
    {print substr($0, index(s, "\t")+1)}
' | xargs -0 cp -t destination

POSIXly, giả sử rằng không có tên tệp nào chứa ký tự dòng mới:

du -ak | sort -k1n | awk '
    (size += $1) > 10*1024*1024 {quit}
    {print substr($0, index(s, "\t")+1)}
' | while IFS= read -r filename; do cp -- "$filename" /path/to/destination

Lưu ý rằng duđi qua các thư mục con. Để tránh điều đó, hãy cho biết dutập tin nào bạn muốn hoạt động. Tổng quát hơn, bạn có thể sử dụng findđể lọc các tập tin.

find . -type f ! -name excluded-file -exec du -ak {} + |
sort -k1n | awk '
    (size += $1) > 10*1024*1024 {quit}
    {print substr($0, index(s, "\t")+1)}
' | while IFS= read -r filename; do cp -- "$filename" /path/to/destination

Có cách nào để thêm rsync như các chức năng không? Điều này sẽ được chạy nhiều lần nhưng tập lệnh này sẽ sao chép các tập tin nhiều lần?
exussum

@ user1281385 Bạn có thể gọi rsyncthay vì cp.
Gilles 'SO- ngừng trở nên xấu xa'

chức năng rysnc sẽ là loại bỏ những cái cũ khi chạy nhiều lần để không chuyển tập tin nếu đã tồn tại
exussum
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.