¿Cómo reemplazar una carpeta cuyo nombre es una fecha, es decir, AAAAMMDD con la jerarquía de carpetas de año, mes, fecha?

Tengo una lista de carpetas que tienen fechas para los nombres. Las fechas tienen el formato AAAAMMDD (por ejemplo, 20150129). Dentro de estas carpetas hay documentos de texto relacionados con esa fecha específica.

Me gustaría reestructurarlos en una jerarquía de carpetas que vaya de un año a otro hasta la fecha, y mover los documentos de texto a la carpeta de 'fecha' correspondiente más abajo en la jerarquía.

En otras palabras, me gustaría que la carpeta 'raíz' tenga el nombre de un año como 2015, y luego cree subcarpetas con nombres de meses como 01, y luego cree subcarpetas adicionales con nombres de fechas como 29 que contengan los documentos de texto correspondientes. .

Entonces el camino se vería como 2015/01/29/file.txto 2015>01>29>file.txt.

He echado un vistazo a Automator y parece que algo así no es posible aunque podría estar equivocado, así que me gustaría saber…

  1. ¿Existe alguna solución fácil para este problema que cualquier profano pueda entender, por ejemplo, un flujo de trabajo de Automator, o esto requiere cierta comprensión de los comandos del terminal y las expresiones regulares?

  2. ¿Cómo se resolvería este problema si de hecho hay una solución?

A quien votó para cerrar esta pregunta como "demasiado amplia", ¿por qué? Tengo curiosidad sobre qué es "demasiado amplio" sobre esta pregunta.
¿Están todas estas carpetas AAAAMMDD directamente dentro de una carpeta maestra o están repartidas en una jerarquía más amplia?
@patrix En mi caso están todos en el mismo directorio o carpeta maestra

Respuestas (2)

Suponiendo que todas estas carpetas AAAAMMDD sean parte del mismo directorio principal que podría ejecutar

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
  • El for d in */; dociclo lee todas las entradas del directorio, el rastreo /asegura que solo los nombres de los directorios realmente coincidan
  • [[ $d =~ [0-9]{8}/ ]]comprueba si la entrada actual consta de 8 dígitos y continúa con la siguiente entrada si no
  • ${d:0:4}/${d:4:2}/${d:6:2}usa la expansión de parámetros dentro bashpara crear una cadena que contiene la nueva ruta
  • El --en ambos mkdiry mvevita problemas en caso de que el directorio o el nombre del archivo comience con una extensión -. Esto no puede suceder aquí, pero probablemente sea una buena práctica de todos modos.

Gracias a @terdon y @user3439894 por sus ideas sobre cómo mejorar el guión original.

Gracias por la respuesta, esto funciona perfectamente! Siento que esta solución es mejor que la provista por @grgarside porque es mucho más rápida, especialmente cuando se trata de un corpus masivo que incluye miles de documentos de texto.

Puede usar lo siguiente en Terminal. cda la carpeta que lo contiene, luego ejecute lo siguiente:

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 fobtiene todos los archivos en el directorio actual recursivamente.
-exec bash -cabre un shell para ejecutar los siguientes comandos.
F=$(…)abre una subcapa y usa sed en la ruta del archivo para manipular la ruta a las carpetas.
^\./([0-9]{4})([0-9]{2})([0-9]{2})es una expresión regular con tres grupos de captura, de la siguiente manera: es reemplazo, donde cada grupo de captura ( , etc.) está separado por . crea los directorios para mover los archivos. mueve cada archivo a su carpeta correspondiente.
\1/\2/\3\1/
mkdir -p -- $(dirname "$F")
mv -- "$1" "$F"

Esto toma la jerarquía de la izquierda y la convierte en la jerarquía de la derecha:

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

Si hay otros archivos en la carpeta contenedora con una fecha como nombre, se moverán como si fueran una carpeta. Para evitar esto, reemplace la segunda línea con:

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

El (?:/.+)garantiza que la ruta tenga un componente subsiguiente, por lo tanto, ignora todo lo que no tenga un elemento secundario en el directorio principal, que son archivos.

@klanomath regex101.com
@grgarside Gracias