rsync最新のx GB


8

最近変更されたファイル(最大10 GB)を別のコンピューターにコピーできるようにするコマンド/スクリプトを探しています。

したがって、4 GBのファイルがそれぞれ4 GBある場合、スクリプトによって転送されるのは2つだけです。1GBのファイルが12個ある場合は、最新の10個だけが転送されます。


1
これを行う方法は考えられませんが、質問を明確にするために、最近変更された10 GBのファイルをコピーしますか、それとも最大10 GBのファイルのセットをコピーしますか?rsyncに最新のファイルを優先させる方法はないと思います。私が考えることができる最も近い答えは、帯域幅を既知の値(1MB /秒など)に制限し、x GBのデータを転送するのに十分な時間が経過した後にrsyncを強制終了することです。帯域幅の制約は最大値であるため、完全ではないため、必要なだけ転送できない可能性があります。
ジョニー

最新。ファイルmtimeによる
exussum 2013年

回答:


6

これは、要求したことを実行するスクリプトです。

要求事項

  • 転送されるファイルの合計は、しきい値サイズ未満である必要があります。
  • ファイルは、rsync宛先と比較して変更する必要があります。
  • すべてのファイルを転送できない場合は、最後に変更されたファイルのみを選択する必要があります。

詳細

rsync --dry-run転送されるファイルのリストを作成するために使用します(これらは変更されたファイルです)。その後の組み合わせを使用duし、lsファイルサイズとmtimeのを取得します。次に、ファイルをmtimeでソートし、合計サイズがしきい値を超えるまでループします。最後に、最後に変更され、合計サイズがしきい値を下回っているファイルのみを使用して、rsyncを再度呼び出します。

スクリプトは少し見苦しいですが、動作します。1つの大きな制限は、rsyncのコピー元ディレクトリを含むマシンで実行する必要があることです。sshを使用してリモートのfrom-directoryを使用するように変更できますが、そのexcersizeはリーダーに任されています。

最後に、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


あなたは、常に最初のファイルは内部で最終ループで、しきい値にかかわらず、転送したい場合はif (( "$size" > "$THRESHOLD" ))、条件の追加(前のチェックbreakのために)i==0そうであれば、echo $f >> /tmp/rsyncfilelist
ケーシー

1

新しいファイルのリストを取得するには、rsync "--dry-run"(または "-n")を使用します。次に、オプション「--files-from =-」を指定して別のrsyncを使用し、ファイルを送信します。中間には「醜い」perlがあります。
このようなもの :

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

編集:私はこの最初の解決策がファイルをmtimeでソートしないことに注意しました、これはより完全な解決策です(他の人が投稿した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";
}

0

のソートされた出力を解析できます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

関数のようなrsyncを追加する方法はありますか?これは複数回実行されますが、このスクリプトはファイルを複数回コピーしますか?
exussum 2013年

@ user1281385のrsync代わりに呼び出すことができますcp
Gilles「SO-悪をやめなさい」

rysnc関数は、ファイルが既に存在する場合にファイルを転送しないように、複数回実行したときに古いファイルを削除します
exussum
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.