Suchen Sie nach Dateien mit ähnlichen Namen, löschen Sie die ältesten, benennen Sie die neuesten

Suchen Sie nach Dateien mit ähnlichen Namen, löschen Sie die ältesten, benennen Sie die neuesten

Ich habe diese Situation, in der es viele Dateien mit ähnlichen Namen (aber sie folgen alle einem Muster) in verschiedenen Unterordnern gibt

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

Jede Datei befindet sich im selben Ordner wie ihre Kopie und hat dieselbe Erweiterung. Der Unterschied besteht darin, dass sie (Copy)am Ende des Namens

Ich möchte alle diese Dateien abrufen und die älteste löschen und die Datei anschließend, falls eine Umbenennung erforderlich ist, von beispielsweise in umbenennen (das heißt, das Suffix file1 (Copy)entfernen file1) .(Copy)

Ich habe überlegt, findund zu verwenden mv, bin mir aber nicht sicher, wie ich ihm sagen kann, dass es das Aktuellste verschieben soll.

Antwort1

Erweitertfind+bashLösung (benötigt auch die GNU-Implementierung von 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%/*}"- Dateipfad/Pfad mit gekürztem Basisnamen
  • bn="${0##*/}"- Basisname der Datei
  • main_bn="${bn/ (Copy)/}"- Entfernen Sie (Copy)einen Teilstring aus dem Basisnamen, um denHaupt-/gemeinsameBasisname
  • if [ -f "$p/$main_bn" ]- wenn dieHaupt-/OriginalDatei existiert (und wird nach der Symlink-Auflösung als reguläre Datei erkannt)
    • t_copy_file=$(stat -c %Y "$0")- Letzte Änderungszeit des gefundenen Objekts abrufen"Kopieren"Datei
    • t_main_file=$(stat -c %Y "$p/$main_bn")- Letzte Änderungszeit abrufen vonOriginalDatei
    • if [[ $t_copy_file -gt $t_main_file ]]- wenn die"Kopieren"Datei ist die neueste - verschieben Sie sie in dieOriginaleins (mach esOriginal) mitmv "$0" "$p/$main_bn"
    • ansonsten derOriginalDatei ist die neueste, entfernen Sie "Kopieren" Datei mitrm "$0"

Oder etwas kürzer mit -ntdem Dateitestoperator ( [ new­er­file –nt olderfile ]- prüfen, ob newerfilees neueren Datums ist als olderfile, oder ob newerfilees existiert, aber olderfilenicht):

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' {} \;

Antwort2

Möglicherweise ist es einfacher mit 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
}

Möglicherweise möchten Sie zunächst überprüfen, ob keine file (Copy) (Copy).txtDateien vorhanden sind.

  • **/: jede Unterverzeichnisebene
  • N:nullglobexpandieren, wenn es keine Übereinstimmung gibt, anstatt einen Fehler zu verursachen
  • D: Einschließen versteckter Dateien ( Doder Dateien) und Absteigen in versteckte Verzeichnisse.
  • .: nur einschließenregulärDateien (kein Verzeichnis, FIFO, Gerät, symbolischer Link …)
  • $file:h:Kopfder Datei (Verzeichnisteil), wie incsh
  • $file:t:Schwanz(Dateiname Teil)
  • ${var/pattern/replacement}, hier ohne Ersatz
  • [[ ! -f $base || -L $base ]] ||...Überspringen Sie als Sicherheitsmaßnahme nicht reguläre Dateien oder symbolische Links (auch wenn sie auf reguläre Dateien verweisen).
  • [ $file -nt $base ]: gibt „true“ zurück, wenn $filezuletzt geändert wurdenach $base(oder $basenicht zugänglich ist, sollte dies nach der obigen Prüfung nicht passieren).

verwandte Informationen