web-dev-qa-db-ja.com

重複するフォルダを「name(1)」、「name(1)(1)」などの構造でマージする方法

Google Filestream、Google Drive、Synology CloudSyncの間で同期すると、すべてが台無しになり、フォルダ名の後に「(1)」や「(2)」などが続く何百もの重複フォルダが残ります。 「(1)(1)(1)」まで。

これらのフォルダをマージできるプログラムまたはスクリプトを知っていますか?

トップレベルのフォルダー構造の例:

1100 Beetledwarf - Happy ATE
1100 Beetledwarf - Happy ATE (1)
1100 Beetledwarf - Happy ATE (2)
1100 Beetledwarf - Happy ATE (3)
1100 Beetledwarf - Happy ATE (3) (1)
1100 Beetledwarf - Happy ATE (3) (1) (1)
1100 Beetledwarf - Happy ATE (4)
1100 Beetledwarf - Happy ATE (5)
1100 Beetledwarf - Happy ATE (6)

サブフォルダーにも同じ問題が発生することがあるため、プログラムまたはスクリプトは、すべてのサブフォルダーのその命名パターンに従うフォルダーをマージできる必要があります。例:

第2レベルのフォルダーの例:

1100 Beetledwarf - Happy ATE (6)
    Analysis
    Analysis (1)
    Smirckle_HL
    Smirckle_HL (2)
    Pending Reports
    Photos & Logos

最善の解決策は、ファイルのコピーに長い時間がかかるが、移動はほとんど瞬時であるため、ファイルをコピーする代わりに移動することもできます。

私がすでに試したことのリストですが、どれも「name(1)」フォルダー構造(これまでのところわかります)を処理できず、すべてファイルを移動する代わりにコピーします。

  • WinMerge for Windows 10 <-Googleドライブファイルをコピーしようとするとチョークします(「DOSコマンドはサポートされていません」のようなものを返します)
  • MacOS用に溶けます。 <-遅い。
  • OSXで「ditto」コマンドを使用するターミナル<-これまでのところ最良のオプション。

ご協力いただきありがとうございます!

1
Josh

以下は、このタスクを実行するbashスクリプトです。それは例えばで動作します。 rsyncが追加されたMSYS2Bash。これは、この関連する質問から抜粋したものです。

特定のサフィックスを持つファイルとフォルダーを重複排除するためのスクリプト

#!/usr/bin/bash
IFS=$'\n';
set -f
#Go deepest first to deal with copies within copied folders.
for copy in $(find . -regextype posix-egrep -regex "^.*\ \([0-9]+\)\s*(\.[^/.]*)?$" | awk '{print length($0)"\t"$0}' | sort -rnk1 | cut -f2-); do
    orig=$(rev <<< "$copy" | sed -E 's/\)[0-9]+\(\ //' | rev)
    if [ "$orig" != "$copy" ]; then
        if [ -f "$orig" ]; then
            if [ -f "$copy" ]; then
                echo "File pair: $orig $copy"
                if diff -q "$orig" "$copy" &>/dev/null; then
                    echo "Removing file: $copy"
                    rm -f "$copy";
                fi
            fi           
        fi
        if [ -d "$orig" ]; then
            if [ -d "$copy" ]; then
                echo "Folder pair: $orig $copy"
                if rmdir "$copy" &>/dev/null; then
                    #If the "copy" was an empty directory then we've removed it and so we're done.
                    echo "Removed empty folder: $copy"
                else
                    #Non-destructively ensure that both folders have the same files at least.                    
                    rsync -aHAv --ignore-existing "$orig/" "$copy" &>/dev/null
                    rsync -aHAv --ignore-existing "$copy/" "$orig" &>/dev/null
                    if diff -qr "$orig" "$copy" &>/dev/null; then
                        echo "Removing folder: $copy"
                        rm -rf "$copy";
                    fi            
                fi
            fi
        fi
    fi
done
unset IFS;
set +f
1
cfp

これは私がLinuxで試みるアプローチです。 Google Filestream、Google Drive、Synology CloudSyncの経験がないので、ソリューションを適用できるかどうかわかりません。それでも、これが少なくともあなたにいくつかのアイデアを与えることを願っています。


仮定

  • ディレクトリツリーに共有をマウントできるため、mvcp、およびその他の適切なツールは、ディレクトリがローカルであるかのように機能します。
  • すべての_(N)_文字列を削除した後にパスが同一になるファイル(またはディレクトリ)は、実際には同じファイル(ディレクトリ)のインスタンスです。
  • 同じファイルのインスタンスは、1つのファイルだけを残す必要があります。
  • 同じディレクトリのインスタンスは、それらのコンテンツを単一のディレクトリにマージする必要があります。
  • ここで使用するすべてのツールを使用できます。

手順

何かをしようとする前に、答え全体を読んでください。

いくつかのステップはスクリプトとして書くことができると思いますが、解決策は非常に実験的なので、手作業で、ステップバイステップで、支払いを行う方が良いです何が起こるかに注意してください。

  1. シェルでcdをマウントポイントに移動し、_find . | vidir -_を呼び出します。選択したテキストエディタを使用します。例: kate、このように:

    _find . | EDITOR=kate vidir
    _

    これにより、すべてのオブジェクトのリストが表示されたエディターが開きます。各オブジェクトの前には独自の番号が付いています。コンテンツを変更して(一時)ファイルを保存し、エディターを閉じると、すべての変更が適用されます。一般的に、これはあなたができることです:

    • ファイルまたはディレクトリを移動(名前変更)するためのパスを変更します。
    • 行を削除してファイルまたはディレクトリを削除します。
    • 2つ以上の番号を交換してファイルを交換します(必要ありません)。

    新しいコンテンツが取得したいディレクトリツリーを記述していることが確実でない限り、ファイルを保存しないでください。

  2. エディターから別のファイルにコンテンツをコピーします。重要なのは、それを操作して、正しいことが確実な場合にのみ結果を貼り付ける(そして保存する)ことです。次の手順では、特に明記されていない限り、新しいファイルを参照します。

  3. sedまたはその他のツールを使用して、すべての_(N)_文字列を削除します(先頭のスペースに注意してください)。この時点で、「クリーンな」パスを取得する必要があります。それらの多くは複数回発生します(vidirで指定された異なる番号で)。

  4. _sort -k 2_を使用して、これらのパスに従って並べ替えます。 _-s_のおかげで、前者のAnalysisは前者のAnalysis (1)の前にあるはずです。

  5. 重複したパスを削除するには、_uniq -f 1_を使用します。これで、パスは1回だけ発生するはずです。

  6. 結果にエンコードされたディレクトリ構造の健全性を再確認してください。

  7. 結果を元のエディターに貼り付け、ファイルを保存してエディターを終了します。 vidirは、欠落している番号に関連付けられているオブジェクトを削除し、残っている番号に関連付けられているオブジェクトを移動します。


テスト

私は最初に このソリューション を使用してディレクトリ構造を複製します:

_cp -a --attributes-only /mountpoint/ /guinea_pig_dir/
_

結果の空のファイルで手順をテストします。これにより、問題(ある場合)が明らかになり、うまくいけばメソッドの改善が可能になります。


考えられる問題

  1. vidirは、一部の非標準文字の操作を拒否します。

  2. 一般に、オブジェクトの順序は重要です。 fooとの衝突時に、_foo~_または_foo~1_、_foo~2_などのオブジェクトを生成する落とし穴はほとんどありません。衝突が発生しないようにディレクトリツリーを「縮小」しますが、考えられるすべてのシナリオを調査したわけではありません。 _/guinea_pig_dir/_を試して、何が得られるかを確認する必要があると思います。トラブルの場合多分sortfindの間の賢いvidirが役に立ちます。

1

次のスクリプトはOSXで機能しますが、いくつかの問題があります。

Googleドキュメントがコピーされないことがあるため、フォルダは差分テストに失敗し、削除されません。次に、それらに対して手動でdiffを実行し、違いがすべてGoogleドキュメントであることを確認し、Googleドキュメントが元のフォルダーにない場合は手動で移動してから、重複するフォルダーを手動で削除する必要があります。 (注:Finderからは、同じドキュメントをコピーできません。これは、以前にgoogle docsファイルをコピーした(またはオプション+ドラッグした)ように感じるため、奇妙に思えます。)

#!/usr/bin/bash
IFS=$'\n';
set -f
#Go deepest first to deal with copies within copied folders.
for copy in $(find -E . -regex "^.*\ \([0-9]+\)\s*(\.[^/.]*)?$" | awk '{print length($0)"\t"$0}' | sort -rnk1 | cut -f2-); do
    orig=$(rev <<< "$copy" | sed -E 's/\)[0-9]+\(\ //' | rev)
    if [ "$orig" != "$copy" ]; then
        if [ -f "$orig" ]; then
            if [ -f "$copy" ]; then
                echo "File pair: $orig $copy"
                if diff -q "$orig" "$copy" &>/dev/null; then
                    echo "Removing file: $copy"
                    rm -f "$copy";
                fi
            fi           
        fi
        if [ -d "$orig" ]; then
            if [ -d "$copy" ]; then
                echo "Folder pair: $orig $copy"
                if rmdir "$copy" &>/dev/null; then
                    #If the "copy" was an empty directory then we've removed it and so we're done.
                    echo "Removed empty folder: $copy"
                else
                    #Non-destructively ensure that both folders have the same files at least.                    
                    rsync -aHAv --ignore-existing "$orig/" "$copy" &>/dev/null
                    rsync -aHAv --ignore-existing "$copy/" "$orig" &>/dev/null
                    if diff -x ‘.*’ -x 'Icon?' -qr "$orig" "$copy" &>/dev/null; then
                        echo "Removing folder: $copy"
                        trash -v "$copy"      # requires that ALi Rantakari's app is installed: aka that you have already run 'brew install trash'
                        #replaced the following: rm -rf "$copy";
                    fi            
                fi
            fi
        fi
    fi
done
unset IFS;
set +f

注:この作業は、このページで詳しく説明されているように、インストールされている次のツールに依存している可能性があります: https://www.topbug.ne​​t/blog/2013/04/14/install-and-use-gnu-command -line-tools-in-mac-os-x /

/usr/bin/Ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install coreutils
export PATH="$(brew --prefix coreutils)/libexec/gnubin:/usr/local/bin:$PATH"
brew tap homebrew/dupes
brew install binutils
brew install diffutils
brew install ed --with-default-names
brew install findutils --with-default-names
brew install gawk
brew install gnu-indent --with-default-names
brew install gnu-sed --with-default-names
brew install gnu-tar --with-default-names
brew install gnu-which --with-default-names
brew install gnutls
brew install grep --with-default-names
brew install gzip
brew install screen
brew install watch
brew install wdiff --with-gettext
brew install wget
brew install bash
brew install rsync
0
Josh