似た名前のファイルを検索し、最も古いファイルを削除し、最新のファイルの名前を変更します

似た名前のファイルを検索し、最も古いファイルを削除し、最新のファイルの名前を変更します

異なるサブフォルダに似た名前のファイルがたくさんある(ただし、すべてパターンに従っている)という状況があります

file1
file1 (Copy)
/folder1/file2.txt
/folder1/file2 (Copy).txt
/folder1/file3.png
/folder1/file3 (Copy).png

各ファイルはコピーの同じフォルダにあり、同じ拡張子を持っていますが、違いは(Copy)名前の末尾に

これらすべてのファイルを取得して最も古いファイルを削除し、名前を変更する必要がある場合は、最終的にファイルの名前を から などに変更しますfile1 (Copy)(file1つまり、サフィックスを削除します)。(Copy)

および を使用することを考えていますfindが、mv最新のものを移動するように指示する方法がわかりません。

答え1

拡張find+bash解決策 (の GNU 実装も必要stat):

find . -type f -name "* (Copy).*" -exec bash -c 'p="${0%/*}"; bn="${0##*/}"; 
        main_bn="${bn/ (Copy)/}"; 
        if [ -f "$p/$main_bn" ]; then 
           t_copy_file=$(stat -c %Y "$0"); t_main_file=$(stat -c %Y "$p/$main_bn"); 
           if [[ $t_copy_file -gt $t_main_file ]]; then 
               mv "$0" "$p/$main_bn"; 
           else
               rm "$0"; 
           fi; 
        fi' {} \;

  • p="${0%/*}"- ファイルパス/ベース名を省略したパス
  • bn="${0##*/}"- ファイルのベース名
  • main_bn="${bn/ (Copy)/}"-(Copy)ベース名から部分文字列を削除してメイン/共通ベース名
  • if [ -f "$p/$main_bn" ]- もしメイン/オリジナルファイルが存在する(そしてシンボリックリンク解決後に通常のファイルであることが判明)
    • t_copy_file=$(stat -c %Y "$0")- 見つかったものの最終変更時刻を取得します"コピー"ファイル
    • t_main_file=$(stat -c %Y "$p/$main_bn")- 最終更新時刻を取得するオリジナルファイル
    • if [[ $t_copy_file -gt $t_main_file ]]- もし"コピー"ファイルは最新のものです - それをオリジナル1つ(作るオリジナル) とmv "$0" "$p/$main_bn"
    • そうでなければオリジナルファイルは最新のもので、「コピー「ファイル」rm "$0"

-ntまたは、ファイル テスト演算子 ( -が より最近変更されたかどうか、またはが存在しないかを[ new­er­file –nt olderfile ]チェック)を使用すると、少し短くなります。newerfileolderfilenewerfileolderfile

find . -type f -name "* (Copy).*" -exec bash -c 'p="${0%/*}"; bn="${0##*/}"; 
        main_bn="${bn/ (Copy)/}"; 
        if [ -f "$p/$main_bn" ]; then 
           if [ "$0" -nt "$p/$main_bn" ]; then 
               mv "$0" "$p/$main_bn"; 
           else
               rm "$0"; 
           fi; 
        fi' {} \;

答え2

次のようにすると簡単になりますzsh:

setopt extendedglob # best in ~/.zshrc
for file (./**/?*" (Copy)"*(ND.)) {
  base=$file:h/${${file:t}/" (Copy)"}}
  [[ ! -f $base || -L $base ]] ||
    if [ $file -nt $base ]; then
      mv $file $base
    else
      rm -f $file
    fi
}

まずファイルがないことを確認してくださいfile (Copy) (Copy).txt

  • **/: 任意のレベルのサブディレクトリ
  • N:ヌルグロブ一致するものがない場合、エラーではなく何も展開しない
  • D: 隠しファイル ( Dot ファイル) を含め、隠しディレクトリに降ります。
  • .: のみ含む通常ファイル (ディレクトリ、FIFO、デバイス、シンボリックリンクなし...)
  • $file:h:ファイル(ディレクトリ部分)のcsh
  • $file:t:しっぽ(ファイル名部分)
  • ${var/pattern/replacement}、ここでは代替品はありません
  • [[ ! -f $base || -L $base ]] ||...安全策として、非通常のファイルまたはシンボリックリンク (通常のファイルを指している場合でも) をスキップします。
  • [ $file -nt $base ]:$file最後に変更された場合はtrueを返します $base(または$baseアクセスできない場合は、上記のチェックに従っても発生しないはずです)。

関連情報