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.