
最近変更されたファイルを最大10 GBまで他のコンピュータにコピーできるコマンド/スクリプトを探しています。
したがって、4 GBのファイルが4つある場合、スクリプトはそのうちの2つのみを転送する必要があり、1GBのファイルが12の場合は最新の10のファイルのみを転送する必要があります。
答え1
以下は、目的のタスクを実行するスクリプトです。
必要
- 送信されるファイルの総数は、しきい値サイズより小さくなければなりません。
- rsyncターゲットとは異なり、これらのファイルは変更する必要があります。
- すべてのファイルを転送できない場合は、最後に変更されたファイルのみを選択できます。
詳細
rsync --dry-run
転送するファイルのリストを作成するために使用されます (修正されたファイル)。次に、du
との組み合わせを使用してls
ファイルサイズと実行時間を取得します。次に、ファイルをmtimeでソートし、全体のサイズがしきい値を超えるまでファイルを繰り返します。最後に、最近修正され、合計サイズがしきい値より小さいファイルのみを使用してrsyncを再呼び出しします。
スクリプトは少し見苦しいですが動作します。 1つの制限は、ディレクトリのrsyncを含むシステムで実行する必要があることです。 SSHを使用してリモートディレクトリを使用するように変更できますが、この練習のサイズは読者によって異なります。
最後に、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
答え2
私は使用します同期「--dry-run」(または「-n」)は最新のファイルのリストを取得します。それでは他のものを使います。同期ファイルを送信するには、「--files-from=-」オプションを使用してください。真ん中に「ugly」があります。真珠。
このような:
#!/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;
編集:最初の解決策は、次のようにファイルをソートしないことがわかりました。時間、ここにはより完全なソリューションがあります(他の人が投稿した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";
}
答え3
解析できるソートされた出力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