rsync 최근 xGB

rsync 최근 xGB

최근 수정된 파일을 최대 10GB까지 다른 컴퓨터에 복사할 수 있는 명령/스크립트를 찾고 있습니다.

따라서 4GB 파일이 4개 있으면 스크립트는 그 중 2개만 전송해야 하고, 1GB 파일이 12개 있으면 가장 최근 파일 10개만 전송해야 합니다.

답변1

다음은 원하는 작업을 수행하는 스크립트입니다.

필요하다

  • 전송된 총 파일 수는 임계값 크기보다 작아야 합니다.
  • rsync 대상과 달리 이러한 파일은 수정되어야 합니다.
  • 모든 파일을 전송할 수 없는 경우 가장 최근에 수정된 파일만 선택할 수 있습니다.

세부 사항

rsync --dry-run전송할 파일 목록을 작성 하는 데 사용됩니다 (수정된 파일). 그런 다음 du및 의 조합을 사용하여 ls파일 크기와 실행 시간을 가져옵니다. 그런 다음 파일을 mtime별로 정렬하고 전체 크기가 임계값을 초과할 때까지 파일을 반복합니다. 마지막으로 최근에 수정되었으며 전체 크기가 임계값보다 작은 파일만 사용하여 rsync를 다시 호출합니다.

스크립트가 약간 보기 흉하지만 작동합니다. 한 가지 제한 사항은 디렉터리의 rsync가 포함된 시스템에서 실행되어야 한다는 것입니다. SSH를 사용하여 원격 디렉토리를 사용하도록 수정할 수 있지만 이 연습의 크기는 독자에게 달려 있습니다.

마지막으로 rsync옵션은 스크립트에 하드코딩되어 있지만 명령줄에서 옵션을 지정하려면 간단히 변경하면 됩니다. 또한 크기를 계산하는 수학은 바이트 단위로 수행됩니다. du 호출을 수정하고 동일한 요소로 임계값을 줄여 킬로/메가바이트/기가바이트로 변경할 수 있습니다.

용법

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

여기서 rsync-from-directory는 로컬 디렉터리이고 rsync-to-directory는 로컬 또는 원격 디렉터리입니다. 기본 옵션은 로 하드코딩되고 -avz기본 임계값은 으로 하드코딩됩니다 10GiB.

스크립트

#!/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

답변2

나는 사용할 것이다동기화"--dry-run"(또는 "-n")은 최신 파일 목록을 가져옵니다. 그러면 다른 것을 사용하겠습니다.동기화파일을 보내려면 "--files-from=-" 옵션을 사용하세요. 중간에 "ugly"가 있어요진주.
이 같은:

#!/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", $_;
        }
}

10GB가 넘는 데이터로 테스트하지 않았습니다. Perl이 어느 정도 한계에 도달했을 수 있습니다. 이 문제를 해결하려면 바이트를 계산하는 데 Kbytes를 사용하지 마세요.

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

편집: 첫 번째 솔루션은 다음과 같은 방식으로 파일을 정렬하지 않는 것으로 나타났습니다.시간, 여기에 더 완전한 솔루션이 있습니다(다른 사람이 게시한 bash 스크립트와 유사).

#!/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";
}

답변3

구문 분석할 수 있는 정렬된 출력입니다 du. 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에서는 파일 이름에 개행 문자가 포함되어 있지 않다고 가정합니다.

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

하위 디렉터리를 탐색하는 데 주의하세요 du. 이를 방지하려면 du작업하려는 파일을 알려주십시오. 보다 일반적으로 파일을 필터링하는 데 사용할 수 있습니다 find.

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

관련 정보