sincronizza i più recenti x GB


8

Sto cercando un comando / script per consentire la copia degli ultimi file modificati (fino a) 10 GB su un altro computer.

Quindi, se ci sono 4 file da 4 GB ciascuno, solo 2 di essi dovrebbero essere trasferiti dallo script, se ci sono 12 file da 1 GB di dimensione, dovrebbero essere trasferiti solo i 10 più recenti.


1
Non riesco a pensare ad alcun modo per farlo, ma per chiarire la tua domanda, vuoi davvero copiare i file da 10 GB modificati più di recente o un set di file fino a 10 GB? Non credo che ci sia modo di forzare rsync a dare priorità ai file più recenti. La risposta più vicina a cui riesco a pensare sarebbe quella di limitare la larghezza di banda a un valore noto (come 1 MB / secondo) e uccidere rsync dopo che è trascorso abbastanza tempo per trasferire x GB di dati. Non perfetto poiché il vincolo di larghezza di banda è un valore massimo, quindi non è possibile trasferire quanto desiderato.
Johnny,

il più recente. per file mtime
exussum,

Risposte:


6

Ecco una sceneggiatura che fa esattamente quello che hai chiesto.

I requisiti

  • I file trasferiti devono avere una dimensione inferiore a una soglia.
  • I file devono essere modificati rispetto alla destinazione rsync.
  • Se non è possibile trasferire tutti i file, è necessario selezionare solo i file modificati più di recente.

I dettagli

Usa rsync --dry-runper creare un elenco di file che verrebbero trasferiti (questi sono i file modificati). Quindi utilizza una combinazione di due lsper ottenere dimensioni dei file e mtime. Quindi ordina i file in base a mtime e quindi passa su di essi fino a quando la dimensione totale supera una soglia. Infine, chiama di nuovo rsync con solo i file che sono stati modificati più di recente e le dimensioni totali al di sotto della soglia.

La sceneggiatura è un po 'brutta, ma funziona. Una grande limitazione è che deve essere eseguito sulla macchina contenente la directory froms di rsync. Può essere modificato per usare ssh per usare una directory remota da, ma quel excersize è lasciato al lettore.

Infine, le rsyncopzioni sono codificate nello script, ma questa è una modifica facile se si desidera specificarle sulla riga di comando. Inoltre, la matematica per calcolare la dimensione viene eseguita in byte. Questo può essere cambiato in chilo / mega / gigabyte modificando la chiamata in du e riducendo la soglia dello stesso fattore.

uso

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

dove rsync-from-directoryè una directory locale ed rsync-to-directoryè qualsiasi directory locale o remota. Le opzioni predefinite sono codificate come -avze la soglia predefinita è codificata come 10GiB.

Il copione

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

Funziona alla grande, una volta non funziona è quando c'è un file più grande di 10 GB come file più recente
esussum

Se si vuole sempre il primo file per trasferire indipendentemente dalla soglia, nel ciclo finale all'interno del if (( "$size" > "$THRESHOLD" ))add condizionale di un controllo (prima break) per i==0e in caso affermativo, echo $f >> /tmp/rsyncfilelist.
Casey,

1

Vorrei usare rsync "--dry-run" (o "-n") per ottenere l'elenco dei file più recenti. Quindi userei un altro rsync con l'opzione "--files-from = -" per inviare i file. Nel mezzo c'è il "brutto" perl .
Qualcosa come questo :

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

Nota non ho testato con più di 10 GB, forse il perl traboccerà ad un certo limite; per risolverlo, invece di contare i byte usa Kbyte:

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

EDIT: ho notato che questa prima soluzione non ordina i file per mtime , ecco una soluzione più completa (simile allo script bash che è stato pubblicato da un'altra persona).

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

È possibile analizzare l'output ordinato di du. Supponendo che le utility 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, supponendo che nessun nome di file contenga un carattere di nuova riga:

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

Si noti che duattraversa le sottodirectory. Per evitarlo, indica su duquali file vuoi operare. Più in generale, è possibile utilizzare findper filtrare i file.

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'è un modo per aggiungere funzioni simili a rsync? questo verrà eseguito più di una volta ma questo script copierà i file più volte?
esussum

@ user1281385 Puoi chiamare rsyncinvece di cp.
Gilles 'SO- smetti di essere malvagio'

la funzione rysnc sarebbe quella di rimuovere quelle vecchie quando eseguite più volte per non trasferire il file se già esiste
esussum
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.