Wie ersetze ich einen Ordner, dessen Name ein Datum ist, dh JJJJMMTT, durch die Ordnerhierarchie von Jahr, Monat, Datum?

8

Ich habe eine Liste von Ordnern, die Daten für Namen haben. Die Daten haben das Format JJJJMMTT (zB 20150129). In diesen Ordnern befinden sich Textdokumente, die sich auf dieses bestimmte Datum beziehen.

Ich möchte sie in einer Ordnerhierarchie von Jahr zu Monat bis heute umstrukturieren und die Textdokumente in den entsprechenden 'Datums'-Ordner weiter unten in der Hierarchie verschieben.

Mit anderen Worten, ich möchte, dass der Ordner 'root' nach dem Jahr wie 2015 benannt wird, und dann Unterordner mit Monaten wie 01 und dann weitere Unterordner mit Datumsangaben wie 29 erstellen, die die entsprechenden Textdokumente enthalten .

Der Weg würde also so aussehen 2015/01/29/file.txtoder 2015>01>29>file.txt.

Ich habe mir Automator angesehen und es scheint, dass so etwas nicht möglich ist, obwohl ich mich irren könnte, also würde ich gerne wissen ...

  1. Gibt es eine einfache Lösung für dieses Problem, die jeder Laie verstehen kann, beispielsweise einen Automator-Workflow, oder erfordert dies ein gewisses Verständnis der Terminalbefehle und regulären Ausdrücke?

  2. Wie würde man dieses Problem lösen, wenn es tatsächlich eine Lösung gibt?

davidjnatarajan
quelle
Wer auch immer dafür gestimmt hat, diese Frage als "zu weit gefasst" zu schließen, warum? Ich bin gespannt, was an dieser Frage "zu weit gefasst" ist.
user3439894
Befinden sich diese JJJJMMTT-Ordner alle direkt in einem Hauptordner oder sind sie über eine breitere Hierarchie verteilt?
Nohillside
@patrix In meinem Fall befinden sie sich alle im selben Verzeichnis oder Master-Ordner
davidjnatarajan

Antworten:

8

Angenommen, alle diese JJJJMMTT-Ordner sind Teil desselben übergeordneten Verzeichnisses, das Sie ausführen könnten

cd PARENT_DIRECTORY
for d in */; do
    [[ $d =~ [0-9]{8}/ ]] || continue
    mkdir -p -- "${d:0:4}/${d:4:2}"
    mv -- "$d" "${d:0:4}/${d:4:2}/${d:6:2}"
done
  • Die for d in */; doSchleife liest alle Verzeichniseinträge, die Nachverfolgung /stellt sicher, dass nur die Verzeichnisnamen tatsächlich übereinstimmen
  • [[ $d =~ [0-9]{8}/ ]] Testet, ob der aktuelle Eintrag aus 8 Ziffern besteht, und fährt mit dem nächsten Eintrag fort, wenn nicht
  • ${d:0:4}/${d:4:2}/${d:6:2}Verwendet die Parametererweiterung innerhalb bash, um eine Zeichenfolge zu erstellen, die den neuen Pfad enthält
  • Das --in beiden mkdirund mvverhindert Probleme, falls das Verzeichnis oder der Dateiname mit a beginnt -. Das kann hier nicht passieren, aber es ist wahrscheinlich trotzdem eine gute Übung.

Vielen Dank an @terdon und @ user3439894 für Ideen zur Verbesserung des ursprünglichen Skripts.

nohillside
quelle
Danke für die Antwort, das funktioniert perfekt! Ich bin der Meinung, dass diese Lösung besser ist als die von @grgarside, da sie viel schneller ist, insbesondere wenn es sich um ein umfangreiches Korpus mit Tausenden von Textdokumenten handelt.
Davidjnatarajan
8

Im Terminal können Sie Folgendes verwenden. cdFühren Sie dann den folgenden Ordner aus:

find . -type f -exec bash -c \
  'F=$(sed -E "s#^\./([0-9]{4})([0-9]{2})([0-9]{2})#\1/\2/\3#" <<< $1);\
  mkdir -p -- $(dirname "$F");\
  mv -- "$1" "$F"' - {} \;

find . -type fRuft jede Datei im aktuellen Verzeichnis rekursiv ab.
-exec bash -cöffnet eine Shell, um die folgenden Befehle auszuführen.
F=$(…)Öffnet eine Subshell und verwendet sed im Dateipfad, um den Pfad in die Ordner zu bearbeiten.
^\./([0-9]{4})([0-9]{2})([0-9]{2})ist eine Regex mit drei Erfassungsgruppen wie folgt: Ersetzt, wobei jede Erfassungsgruppe ( usw.) durch getrennt ist . Erstellt die Verzeichnisse, in die die Dateien verschoben werden sollen. verschiebt jede Datei in den entsprechenden Ordner.
\1/\2/\3\1/
mkdir -p -- $(dirname "$F")
mv -- "$1" "$F"

Dadurch wird die Hierarchie links in die Hierarchie rechts konvertiert:

├── 20170201               └── 2017
   └── abcdefghij             ├── 02
└── 20170302                      └── 01
    └── abcdefghij 2                  └── abcdefghij
                               └── 03
                                   └── 02
                                       └── abcdefghij 2

Wenn sich im enthaltenden Ordner andere Dateien mit einem Datum als Namen befinden, werden sie so verschoben, als wären sie ein Ordner. Um dies zu verhindern, ersetzen Sie die zweite Zeile durch:

  'F=$(sed -E "s#^\./([0-9]{4})([0-9]{2})([0-9]{2})(?:/.+)#\1/\2/\3#" <<< $1);\

Das (?:/.+)stellt sicher, dass der Pfad eine nachfolgende Komponente hat, und ignoriert daher alles ohne untergeordnetes Element im übergeordneten Verzeichnis, bei dem es sich um Dateien handelt.

grg
quelle
@klanomath regex101.com
grg
@grgarside Thanx
klanomath