rsync最近x GB


8

我正在寻找一个命令/脚本,以允许将最近修改的文件(最大)10GB复制到另一台计算机。

因此,如果每个4 GB的文件有4个,则脚本只能传输其中2个文件;如果1GB大的文件有12个,则仅应传输最近的10个文件。


1
我想不出任何办法,但是为了澄清您的问题,您是否真的要复制最近修改的10GB文件,或者任何一组最多10GB的文件?我不认为有任何方法可以强制rsync将最新文件赋予优先级。我能想到的最接近的答案是将带宽限制到一个已知值(例如1MB /秒),并在经过足够的时间来传输x GB数据后终止rsync。由于带宽限制是最大值,因此并不完美,因此您可能传输的传输量可能不够。
约翰尼,

最近的。由文件mtime
exussum 2013年

Answers:


6

这是一个满足您要求的脚本。

要求

  • 传输的文件总数必须小于阈值大小。
  • 与rsync目标相比,必须修改文件。
  • 如果不是所有文件都可以传输,则只能选择最近修改的文件。

细节

它用于rsync --dry-run构建将要传输的文件(这些文件是修改后的文件)的列表。然后,它使用的组合du,并ls获得文件大小和修改时间。然后,它按mtime排序文件,然后循环遍历文件,直到总大小超过阈值。最后,它仅使用最近修改且总大小在阈值以下的文件再次调用rsync。

该脚本有点丑陋,但是可以用。一个很大的限制是它必须在包含rsync from目录的计算机上执行。可以对其进行修改,以使用ssh来使用远程from目录,但该摘要的大小留给读者。

最后,将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

效果很好,有一次它不起作用,那就是有一个大于10GB的文件作为最新文件
exussum 2013年

如果您始终希望无论阈值如何都传输第一个文件,请在if (( "$size" > "$THRESHOLD" ))条件语句的最后一个循环中(在之前break)添加的检查i==0,如果是,则添加echo $f >> /tmp/rsyncfilelist
casey 2013年

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)'所以

rysnc函数将是多次运行时删除旧文件,而不是不传输文件(如果已存在的话)
exussum
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.