rsync x GB terbaru


8

Saya mencari perintah / skrip untuk memungkinkan file yang paling baru dimodifikasi (hingga) 10GB disalin ke komputer lain.

Jadi jika ada 4 file masing-masing 4 GB, hanya 2 dari mereka harus ditransfer oleh skrip, Jika ada 12 file 1GB besar, hanya 10 yang terbaru yang harus ditransfer.


1
Saya tidak bisa memikirkan cara untuk melakukan ini, tetapi untuk memperjelas pertanyaan Anda, apakah Anda benar-benar ingin 10GB file yang paling baru dimodifikasi disalin, atau set hingga 10GB file? Saya tidak percaya ada cara untuk memaksa rsync untuk memprioritaskan file terbaru. Jawaban terdekat yang dapat saya pikirkan adalah membatasi bandwidth dengan nilai yang diketahui (seperti 1MB / detik) dan membunuh rsync setelah cukup waktu untuk mentransfer x GB data. Tidak sempurna karena batasan bandwidth adalah nilai maksimum sehingga Anda tidak dapat mentransfer sebanyak yang Anda inginkan.
Johnny

paling baru. oleh file mtime
exussum

Jawaban:


6

Berikut adalah skrip yang melakukan apa yang Anda minta.

Persyaratan

  • File yang ditransfer harus berjumlah kurang dari ukuran ambang.
  • File harus dimodifikasi dibandingkan dengan tujuan rsync.
  • Jika tidak semua file dapat ditransfer, hanya file yang paling baru dimodifikasi harus dipilih.

Rinciannya

Ini digunakan rsync --dry-rununtuk membangun daftar file yang akan ditransfer (ini adalah file yang dimodifikasi). Kemudian menggunakan kombinasi dudan lsuntuk mendapatkan ukuran dan waktu file. Ini kemudian mengurutkan file berdasarkan mtime dan kemudian loop di atasnya sampai ukuran total melebihi ambang batas. Akhirnya, ia memanggil rsync lagi hanya dengan file-file yang paling baru-baru ini dimodifikasi dan ukuran total di bawah ambang batas.

Skripnya agak jelek, tapi berhasil. Satu batasan besar adalah harus dijalankan pada mesin yang berisi direktori-rsync. Itu dapat dimodifikasi untuk menggunakan ssh untuk menggunakan remote dari-direktori, tetapi excersize diserahkan kepada pembaca.

Akhirnya, rsyncopsi tersebut dikodekan ke dalam skrip, tetapi ini adalah perubahan yang mudah jika Anda ingin menentukannya di baris perintah. Juga, matematika untuk menghitung ukuran dilakukan dalam byte. Ini dapat diubah menjadi kilo / mega / gigabytes dengan memodifikasi panggilan ke du dan mengurangi ambang dengan faktor yang sama.

Pemakaian

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

di mana rsync-from-directorydirektori lokal dan direktori rsync-to-directorylokal atau jauh. Opsi default adalah hardcoded -avzdan ambang default adalah hardcoded sebagai 10GiB.

Naskah

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

Bekerja dengan baik, Satu kali itu tidak berhasil adalah ketika ada file yang lebih besar dari 10GB sebagai file terbaru
exussum

Jika Anda selalu ingin file pertama ditransfer terlepas dari ambangnya, pada loop terakhir di dalam if (( "$size" > "$THRESHOLD" ))kondisional tambahkan tanda centang (sebelum break) untuk i==0dan jika demikian echo $f >> /tmp/rsyncfilelist,.
Casey

1

Saya akan menggunakan rsync "--dry-run" (atau "-n") untuk mendapatkan daftar file yang lebih baru. Kemudian saya akan menggunakan rsync lain dengan opsi "--files-from = -" untuk mengirim file. Di antara ada perl "jelek" .
Sesuatu seperti ini :

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

Catatan saya tidak menguji dengan lebih dari 10GB, mungkin perl akan meluap pada batas tertentu; untuk mengatasinya, alih-alih menghitung byte gunakan Kbytes:

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

EDIT: Saya mencatat bahwa solusi pertama ini tidak akan mengurutkan file berdasarkan mtime , berikut adalah solusi yang lebih lengkap (mirip dengan skrip bash yang telah diposting oleh orang lain).

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

Anda dapat menguraikan output yang diurutkan dari du. Dengan asumsi utilitas 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, dengan asumsi bahwa tidak ada nama file yang mengandung karakter baris baru:

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

Perhatikan bahwa dumelintasi subdirektori. Untuk menghindarinya, beri tahu dufile mana yang ingin Anda operasikan. Secara umum, Anda dapat menggunakan finduntuk memfilter 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

apakah ada cara untuk menambahkan fungsi seperti rsync? ini akan dijalankan lebih dari sekali tetapi skrip ini akan menyalin file beberapa kali?
exussum

@ user1281385 Anda dapat menelepon rsyncalih-alih cp.
Gilles 'SO- stop being evil'

fungsi rysnc adalah untuk menghapus yang lama ketika dijalankan beberapa kali agar tidak mentransfer file jika sudah ada
exussum
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.