次の手順に従ってスクリプトを完成させてください。 (1)複数のサブディレクトリから最近変更されたファイル1gigを選択します。 (2)rsync
ローカルディレクトリにファイルをコピーするのに最適です。既存のファイルなどをスキップするrsync
機能を使用できるため、cpを好みます。rsync
ステップ1では、次の操作を実行して、1gig制限のある最新のファイルを提供します。
ls -lstrkR /volume1/cctv/* | grep \.mp4$ | awk '
(size += $1) > 1*1024*1024 {exit}
#{print "size=" size "\t" $1 "\t" $6 "\t" $7 " " $8 " "$9 "\t" $10}
{print $10}
'
上記の出力は次のとおりです。file1.mp4 file2.mp4など。
各ファイルの絶対パスはありません。上記のファイルは/volume1/cctvのいくつかのサブディレクトリにあります(ご覧のようにls -R
)。
以下を行う必要があります。 (ㅏ)上記の出力を取得してrsyncにパイプするか、 (二)cpファイル(絶対パスなしでこのリストで作業できますか?)
答え1
このperl
スクリプトは必要な操作を実行する必要があります。 NULで区切られたファイル名のリスト(例:from find -print0
)が与えられると、そのファイルの合計サイズが1GB(デフォルト)を超えない限り、最近変更されたファイル名のリストが出力されます。コマンドラインで公演番号の最大サイズを指定できます。これは有効な数値、整数、または浮動小数点です。
NUL区切り文字は、スペースや改行文字が含まれていてもすべてのファイル名に対して機能することを意味します。
$ cat select-newest-one-gig.pl
#! /usr/bin/perl -0
use strict;
my $gigs = shift || 1;
my $maxsize = $gigs * 1024 * 1024 * 1024 ; # 1GB
my $total = 0;
# a hash to contain the list of input filenames and their modtimes
my %filemtimes=();
# hash to contain the list of input filenames and their sizes
my %filesizes=();
# a hash to contain a list of filenames to output.
# use a hash for this so we don't need to write a `uniq` function.
my %outfiles=();
while (<>) {
chomp;
# 7th field of stat() is size in bytes.
# 9th field of stat() is modime in secs since epoch
my ($size,$mtime) = (stat($_))[7,9];
$filesizes{$_} = $size;
$filemtimes{$_} = $mtime;
}
# iterate through the %filemtimes hash in order of reverse mtime
foreach (reverse sort { $filemtimes{$b} <=> $filemtimes{$a} } keys %filemtimes) {
my $size = $filesizes{$_};
# add it to our list of filenames to print if it won't exceed $maxsize
if (($size + $total) <= $maxsize) {
$total += $size;
$outfiles{$_}++;
}
}
# now iterate through the %filesizes hash in order of reverse size
# just in case we can sequeeze in a few more files.
foreach (reverse sort { $filesizes{$b} <=> $filesizes{$a} } keys %filesizes) {
my $size = $filesizes{$_};
if (($size + $total) < $maxsize) {
$total += $size;
$outfiles{$_}++;
}
}
# now print our list of files. choose one of the following, for
# newline separated filenames or NUL-separated.
#print join("\n", sort keys %outfiles), "\n";
print join("\000", sort keys %outfiles), "\000";
別の名前で保存select-newest-one-gig.pl
して実行可能にしますchmod +x
。
次のように実行します(たとえば、最大合計ファイルサイズは10 GBです)。
find /volume1/cctv/ -type f -iname '*.mp4' -print0 | ./select-newest-one-gig.pl 10
このPerlスクリプトは、1つ以上のファイル拡張子(たとえば.mp4
)を引数として取り、system()
関数呼び出しを使用してfind自体を実行し、代わりに繰り返すように簡単に変更できますwhile (<>)
。出力をパイプに接続する方が簡単ですfind
。なぜ車輪を再発明するのですか?
次のPerlスクリプトは、rsyncターゲットディレクトリにあるファイルを一覧表示します(最後の行のコメントを外した場合は削除します)。いいえ標準入力に表示されます。 NULで区切られた入力を想定しているため、ファイル名に改行文字が含まれていても安全です。
$ cat unlink-others.pl
#! /usr/bin/perl -0
use strict;
my @files=();
# first arg is target dir, with default
my $targetdir = shift || '/path/to/rsync/target/dir/';
while (<>) {
chomp;
s/^.*\///; # strip path
push @files, quotemeta($_)
}
my $regexp=join("|",@files);
opendir(my $dh, $targetdir) || die "can't opendir $targetdir: $!\n";
my @delete = grep { ! /^($regexp)$/o && -f "$targetdir/$_" } readdir($dh);
closedir $dh;
print join(", ",@delete),"\n";
# uncomment next line if you're sure it will only delete what you want
# unlink @delete
次のように使用してください。
find /volume1/cctv/ -type f -iname '*.mp4' -print0 | \
./select-newest-one-gig.pl 10 > /tmp/files.list
rsync --from0 --files-from /tmp/files.list ... /path/to/rsync/target/dir/
./unlink-others.pl /path/to/rsync/target/dir/ < /tmp/files.list
答え2
cd /volume/cctv
echo 0 >/tmp/sztally &&
find .// -name '*.[mM][pP]4' -type f -exec sh -fc '
_cp(){ shift; echo cp "$@$0"; :; }
read sz </tmp/sztally; IFS=/ g=$((1024*1024)); unset _f
for f in $(ls -dkst "$@")
do case $f in
("") f=${2+./${_f%[!0-9. ]*}} _f=${_f##*[pP]4?}
[ 0 -ne "$((g>(sz+${_f%??})))" ] &&
set "$f$@" && sz=$((sz+${_f%??})) _f=;;
(*) [ -z ${_f:+:} ] && set "" ${_f+"$@"}
_f=${_f:+$_f/}$f
esac|| ! _cp "$@" || exit 255
done; _cp "$@"; echo "$sz" >/tmp/sztally
' "/destination/path" {} +
これは私にとって効果的です。私のメディアディレクトリでテストしましたが、常に最新の1GBの.mp4ファイルのみを1つのタスクにcp
まとめました。私の考えls
では、あなたが探しているオプションは、すべてのパラメータのフルパス名を-d
保存することです。ls
ここではfind
、一緒に集めることができるすべての.mp4ファイルを見つけて、ls
変更時間ごとに選択を並べ替えます。シェルはls
パス名の区切り文字である - に従って出力を分割するため、/
ファイル名の特殊文字はまったく考慮されないため、問題になりません。
厳密に言えば-s
、このオプションはls
ファイルサイズを報告しません。使用スペース。 2つの概念は異なる場合がありますが、圧縮されたビデオファイルでは異なる可能性は非常に希薄です。これは実際に作成されたとおりにコピーされません。ただecho
働くだけですcp
。テストして機能していることがわかったら、関数echo
から削除してください。_cp()
ls
これはPOSIX、、、find
によってcp
異なりますsh
。