Come sostituire una cartella il cui nome è una data, ad esempio AAAAMMGG con gerarchia di cartelle di anno, mese, data?


8

Ho un elenco di cartelle che hanno date per i nomi. Le date sono nel formato AAAAMMGG (ad es. 20150129). All'interno di queste cartelle sono presenti documenti di testo correlati a quella data specifica.

Vorrei ristrutturarli in una gerarchia di cartelle che va di anno in mese fino ad oggi e spostare i documenti di testo nella corrispondente cartella 'data' in basso nella gerarchia.

In altre parole, desidero che la cartella "root" sia denominata dopo l'anno come 2015, quindi creare sottocartelle denominate con mesi come 01, quindi creare ulteriori sottocartelle denominate con date come 29 che contengano i documenti di testo corrispondenti .

Quindi il percorso sarebbe simile 2015/01/29/file.txto 2015>01>29>file.txt.

Ho dato un'occhiata ad Automator e sembra che qualcosa del genere non sia possibile, anche se potrei sbagliarmi, quindi vorrei sapere ...

  1. Esiste una soluzione semplice a questo problema che qualsiasi profano può comprendere, ad esempio un flusso di lavoro di Automator, o richiede una certa comprensione dei comandi del terminale e delle espressioni regolari?

  2. Come si risolverebbe questo problema purché in realtà esista una soluzione?


A chi ha votato per chiudere questa domanda come "troppo ampia", perché? Sono curioso di sapere cosa c'è di "troppo ampio" in questa domanda?
user3439894,

Queste cartelle AAAAMMGG sono tutte direttamente all'interno di una cartella principale o sono distribuite su una gerarchia più ampia?
Nohillside

@patrix Nel mio caso sono tutti nella stessa directory o cartella principale
davidjnatarajan

Risposte:


8

Supponendo che tutte queste cartelle AAAAMMGG facciano parte della stessa directory principale che è possibile eseguire

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
  • Il for d in */; dociclo legge tutte le voci della directory, il trailing /assicura che solo i nomi delle directory corrispondano effettivamente
  • [[ $d =~ [0-9]{8}/ ]] verifica se la voce corrente è composta da 8 cifre e, in caso contrario, continua con la voce successiva
  • ${d:0:4}/${d:4:2}/${d:6:2}utilizza l'espansione dei parametri all'interno bashper creare una stringa contenente il nuovo percorso
  • In --entrambi mkdire mvimpedisce il problema nel caso in cui la directory o il nome del file inizi con a -. Questo non può succedere qui, ma probabilmente è comunque una buona pratica.

Grazie a @terdon e @ user3439894 per idee su come migliorare lo script originale.


Grazie per la risposta, funziona perfettamente! Penso che questa soluzione sia migliore di quella fornita da @grgarside perché è molto più veloce, specialmente quando si ha a che fare con un corpus enorme che include migliaia di documenti di testo.
davidjnatarajan,

8

È possibile utilizzare quanto segue in Terminale. cdnella cartella contenente, quindi eseguire quanto segue:

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 fottiene ricorsivamente tutti i file nella directory corrente.
-exec bash -capre una shell per eseguire i seguenti comandi.
F=$(…)apre una subshell e usa sed sul percorso del file per manipolare il percorso nelle cartelle.
^\./([0-9]{4})([0-9]{2})([0-9]{2})è una regex con tre gruppi di acquisizione, come segue: è la sostituzione, in cui ciascun gruppo di acquisizione ( , ecc.) è separato da . crea le directory in cui spostare i file. sposta ciascun file nella cartella corrispondente.
\1/\2/\3\1/
mkdir -p -- $(dirname "$F")
mv -- "$1" "$F"

Questo prende la gerarchia a sinistra e la converte nella gerarchia a destra:

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

Se ci sono altri file nella cartella contenente con una data come nome, verranno spostati come se fossero una cartella. Per evitare ciò, sostituire la seconda riga con:

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

Le (?:/.+)assicura che il percorso ha una componente successiva, quindi, ignorando tutto ciò senza un bambino nella directory superiore, che sono file.


@klanomath regex101.com
grg

@grgarside Thanx
klanomath
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.