rsync aktuell x GB

8

Ich suche nach einem Befehl / Skript, mit dem die zuletzt geänderten Dateien (bis zu 10 GB) auf einen anderen Computer kopiert werden können.

Wenn also 4 Dateien mit jeweils 4 GB vorhanden sind, sollten nur 2 vom Skript übertragen werden. Wenn 12 Dateien mit einer Größe von 1 GB vorhanden sind, sollten nur die letzten 10 Dateien übertragen werden.

Exussum
quelle
1
Ich kann mir keine Möglichkeit vorstellen, dies zu tun, aber um Ihre Frage zu klären, möchten Sie wirklich, dass die zuletzt geänderten 10 GB Dateien kopiert werden oder ein Satz von bis zu 10 GB Dateien? Ich glaube nicht, dass es eine Möglichkeit gibt, rsync zu zwingen, den neuesten Dateien Priorität einzuräumen. Die beste Antwort, die ich mir vorstellen kann, wäre, die Bandbreite auf einen bekannten Wert (wie 1 MB / Sekunde) zu beschränken und rsync zu beenden, nachdem genügend Zeit verstrichen ist, um x GB Daten zu übertragen. Nicht perfekt, da die Bandbreitenbeschränkung ein Maximalwert ist, sodass Sie möglicherweise nicht so viel übertragen, wie Sie möchten.
Johnny
der neuesten. per Datei mtime
exussum

Antworten:

6

Hier ist ein Skript, das genau das tut, wonach Sie gefragt haben.

Die Anforderungen

  • Die übertragenen Dateien müssen weniger als eine Schwellengröße betragen.
  • Die Dateien müssen im Vergleich zum rsync-Ziel geändert werden.
  • Wenn nicht alle Dateien übertragen werden können, müssen nur die zuletzt geänderten Dateien ausgewählt werden.

Die Details

Es wird verwendet rsync --dry-run, um eine Liste der Dateien zu erstellen, die übertragen werden sollen (dies sind die geänderten Dateien). Anschließend wird eine Kombination aus duund verwendet ls, um Dateigröße und Zeit zu ermitteln. Anschließend werden die Dateien nach mtime sortiert und anschließend durchlaufen, bis die Gesamtgröße einen Schwellenwert überschreitet. Schließlich wird rsync erneut aufgerufen, wobei nur die zuletzt geänderten Dateien und die Gesamtgröße unter dem Schwellenwert liegen.

Das Skript ist etwas hässlich, aber es funktioniert. Eine große Einschränkung besteht darin, dass es auf dem Computer ausgeführt werden muss, der das Verzeichnis rsync from enthält. Es kann geändert werden, um ssh zu verwenden, um ein entferntes Verzeichnis zu verwenden, aber diese Übergröße bleibt dem Leser überlassen.

Schließlich sind die rsyncOptionen fest im Skript codiert. Dies ist jedoch eine einfache Änderung, wenn Sie sie in der Befehlszeile angeben möchten. Die Berechnung der Größe erfolgt ebenfalls in Bytes. Dies kann in Kilo / Mega / Gigabyte geändert werden, indem der Anruf auf du geändert und der Schwellenwert um denselben Faktor verringert wird.

Verwendungszweck

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

Dabei rsync-from-directoryhandelt es sich um ein lokales Verzeichnis und rsync-to-directoryum ein lokales oder entferntes Verzeichnis. Die Standardoptionen sind fest codiert als -avzund der Standardschwellenwert ist fest codiert als 10GiB.

Das Skript

#!/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
Casey
quelle
Funktioniert hervorragend. Einmal funktioniert es nicht, wenn eine Datei größer als 10 GB als neueste Datei vorhanden ist
Exussum
Wenn Sie immer möchten, dass die erste Datei unabhängig vom Schwellenwert übertragen wird, if (( "$size" > "$THRESHOLD" ))fügen Sie in der letzten Schleife innerhalb der Bedingung eine Prüfung (vor break) für i==0und wenn ja, hinzu echo $f >> /tmp/rsyncfilelist.
Casey
1

Ich würde rsync "--dry-run" (oder "-n") verwenden, um die Liste der neueren Dateien zu erhalten. Dann würde ich einen anderen rsync mit der Option "--files-from = -" verwenden, um die Dateien zu senden. Dazwischen gibt es "hässliches" Perl .
Etwas wie das :

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

Hinweis: Ich habe nicht mit mehr als 10 GB getestet. Möglicherweise läuft Perl an einem bestimmten Grenzwert über. Um dies zu lösen, verwenden Sie Kbytes, anstatt Bytes zu zählen:

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

BEARBEITEN: Ich habe festgestellt, dass diese erste Lösung die Datei nicht nach mtime sortieren würde. Hier ist eine vollständigere Lösung (ähnlich dem Bash-Skript, das von einer anderen Person veröffentlicht wurde).

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

Sie können die sortierte Ausgabe von analysieren du. Angenommen, GNU-Dienstprogramme:

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 unter der Annahme, dass kein Dateiname ein Zeilenumbruchzeichen enthält:

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

Beachten Sie, dass duUnterverzeichnisse durchlaufen werden. Um dies zu vermeiden, teilen duSie mit , welche Dateien Sie bearbeiten möchten. Im Allgemeinen können Sie findDateien filtern.

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
Gilles 'SO - hör auf böse zu sein'
quelle
Gibt es eine Möglichkeit, rsync-ähnliche Funktionen hinzuzufügen? Dies wird mehr als einmal ausgeführt, aber dieses Skript kopiert die Dateien mehrmals?
Exussum
@ user1281385 Sie können anrufen rsyncstatt cp.
Gilles 'SO - hör auf böse zu sein'
Die rysnc-Funktion wäre, die alten zu entfernen, wenn sie mehrmals ausgeführt werden, um die Datei nicht zu übertragen, wenn sie bereits vorhanden ist
Exussum