lsとawkをrsyncにパイピング

lsとawkをrsyncにパイピング

次の手順に従ってスクリプトを完成させてください。 (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

関連情報