2017-06-07 3 views
1

共有ドライブをリモートで同期させるためにsyncthingを使用していた3つのOSXマシンセットアップがあります。誰かが間違いを犯し、多くのファイルが改名されました。非常に大量のファイルを含むファイル管理のためのスクリプティング

このドライブでは、サイズが0KBのファイル(たとえば、file.jpg)と実際のサイズが file.sync-confilct201705-4528.jpgの別のファイルがある状況があります。ドライブ全体を再帰的に検索し、sync-conflict文字列を含むファイルが見つかったら、 'sync-conflict'文字列がない同じファイルが0KBのサイズであるかどうかを確認します。存在する場合は、0KBファイルを上書きするためにsync-conflictファイルの名前を変更する必要があります。

私はbashスクリプトまたはPerlスクリプトを使ってこれに取り組むことを検討しました。 bashの使用私​​は、-regexで 'find'コマンドを使用するだけで、私を始められると思いますが、結果を処理して次の検索テストを実行する方法はわかりません。私は勉強してそれに取り組んでいます。

Perlにも同じ問題があります。 File :: Findを使って最初のステップを進めることができます:ファイルをフィルタリングするためにregexを使う必要があるものを見つけて選択しますが、同じディレクトリにある元のファイルを見つける次のステップに進んでいます必要なファイル移動機能を実行します。

これらの両方のケースでは、私はそれを理解する時間を置いていきたいと思いますが、警告がどうなるのだろうか?これらのシナリオの両方で、例外なく多数のファイルを再帰的に処理できますか?おそらく誰かがお勧めできるより良いアプローチはありますか?

+2

私の最初の提案は、何かを始める前にバックアップをとることです。 –

+0

ゼロサイズのファイルを最初に検索し、対応する競合ファイルがあるかどうかを確認する方が簡単でしょう。それは問題を完全に解決するわけではないかもしれませんが、良い最初のステップになります。次に、競合ファイルが残っている場合は、競合ファイルが一致する場合は内容を比較し、競合ファイルを削除します。 –

答えて

1

Perlの良いツールの1つは、File::Find::Ruleです。

はその後、すべての sync-conflictファイルを検索し、対応するファイルが存在して存在し、ゼロサイズの両方をテストするゼロサイズ

use warnings; 
use strict; 
use FindBin qw($RealBin); 
use File::Copy qw(move); 
use File::Find::Rule; 

my $dir = shift || '.'; # top of hierarchy to search (from command line, or ./) 

my @conflict_files = File::Find::Rule 
    ->file->name('*sync-conflict*.jpg')->in($dir); 

foreach my $conflict (@conflict_files) 
{ 
    my ($file) = $conflict =~ m|(.*)\.sync-conflict|; 
    $file .= '.jpg'; 

    if (-z "$RealBin/$file") { 
     print "Rename $conflict to $file\n" 
     #move($conflict, $file) or warn "Can't move $conflict to $file: $!"; 
    } 
} 

これは、各file.sync-conflictファイルのファイル名fileを構築し、-zfile test (-X)を適用し、あるかどうかをテストします。次に、コア名File::Copyを使用してファイルの名前を変更します。

ファイルテストオペレータはフルパスを必要とし、File::Find::Ruleは、それが検索する$dirに対するパスを返します。私はFindBinが提供する$RealBinを使用します。これは、すべてのリンクを解決してスクリプトを開始したディレクトリへのパスで、-zの完全パスを構築します。

十分なテストの後で(そして最初にバックアップを作成して)move行のコメントを外します。

コードではファイル名についていくつかの仮定がありますので、必要に応じて調整してください。 コマンドラインで指定された$dirは、スクリプトのディレクトリからの相対パスであることが想定されています。

+0

@ J.P。 'File :: Find :: Rule'が相対パスを提供している間に、ファイルテストオペレータがフルパスを必要とするので、モジュールで返されたものを使用するときは、それを修正する必要があります。 '-z'のフルパス)。それは私があなたの他の質問にコメントとして書いたのと同じことですが、あなたがそれを見たかどうかわからないので、このメモ。他に何かが現れたら教えてください。 – zdim

+0

@ J.Pコードの説明が役に立つかどうか教えてください。 – zdim

+0

ありがとう、私はあなたが言っていることを把握しています。私はあなたの方向性を取り、それまでにうまくいくものをまとめました。私はそれを投稿して嬉しいです。正しいアプローチは何ですか?元の質問を編集し、更新されたコードを投稿するだけでよいですか? –

0

名前を修正する機能を作成します。

$ function fixname() { file="$1"; newname=$(echo "$file" | sed "s/sync-conflict.*\.jpg$/.jpg/"); if [ -f "$newname" -a ! -s "$newname" ]; then mv "$file" "$newname"; fi; } 

か、少し広がっ:

function fixname() { 
    file="$1" 
    newname=$(echo "$file" | sed "s/sync-conflict.*\.jpg$/.jpg/") 
    # If empty file exists 
    if [ -f "$newname" -a ! -s "$newname" ]; then 
     mv "$file" "$newname" 
    fi 
} 

エクスポート機能:

$ export -f fixname 

実行して、機能を実行するために見つけることを:

$ find . -type f -name \*sync-conflict\*.jpg -exec bash -c 'fixname {}' bash \; 

警告:ファイル名にスペースやファンキーな文字は使用できません。

0

findは素晴らしいです。しかし、あなたが指摘したように、より多くのことが必要です。

このシナリオではfindは、再帰的に検索して特定のパターンに一致するものです。 Bashバージョン4のように起こるので、あなたはシェルでそれを行うことができます。

(bashのバージョン3とMacOSの船は、このソリューションのため、あなたはMacportsHomebrewまたはFinkからbashの4をインストールする必要がありますので注意してください。)あなたはechoが実際に実行するために削除することができます

$ shopt -s globstar nullglob 
$ for file in **/*sync-confilct2017*.*; do echo mv -v "$file" "${file%sync-conf*}${file##*.}"; done 
mv -v file.sync-confilct201705-4528.jpg file.jpg 
mv -v foo/bar.sync-confilct201705-4528.ext foo/bar.ext 

mvコマンド

このように動作する方法は、ダブルアスタリスク**は、反復する*のようにbashで処理されます。我々は、 "ターゲット"ファイル名を構築するために必要なファイル名の部分を取り除くためにパラメータ拡張を使用しています。