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

8

Tengo una lista de carpetas que tienen fechas para los nombres. Las fechas están en 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 de año a mes hasta la fecha, y mover los documentos de texto a la carpeta 'fecha' correspondiente más abajo en la jerarquía.

En otras palabras, me gustaría que la carpeta 'raíz' se nombrara después del año como 2015, y luego crear subcarpetas con meses como 01, y luego crear más subcarpetas con 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 como esto 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 laico pueda entender, por ejemplo, un flujo de trabajo de Automator, o esto requiere cierta comprensión de los comandos de terminal y las expresiones regulares?

  2. ¿Cómo se resolvería este problema siempre que haya una solución?

davidjnatarajan
fuente
A quien haya votado para cerrar esta pregunta como "demasiado amplia", ¿por qué? Tengo curiosidad por saber qué es "demasiado amplio" acerca de esta pregunta.
user3439894
¿Estas carpetas AAAAMMDD están todas directamente dentro de una carpeta maestra o están distribuidas en una jerarquía más amplia?
nohillside
@patrix En mi caso, todos están en el mismo directorio o carpeta maestra
davidjnatarajan

Respuestas:

8

Asumiendo que todas estas carpetas AAAAMMDD son parte del mismo directorio padre 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 */; dobucle lee todas las entradas de directorio, el seguimiento /garantiza que solo los nombres de directorio coincidan
  • [[ $d =~ [0-9]{8}/ ]] prueba 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}utiliza la expansión de parámetros dentro bashpara crear una cadena que contiene la nueva ruta
  • El problema --en ambos mkdiry mvpreviene en caso de que el directorio o nombre de archivo comience con a -. 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 script original.

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

Puede usar lo siguiente en la Terminal. cda la carpeta que 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 del directorio actual de forma recursiva.
-exec bash -cabre un shell para ejecutar los siguientes comandos.
F=$(…)abre una subshell y usa sed en la ruta del archivo para manipular la ruta en las carpetas.
^\./([0-9]{4})([0-9]{2})([0-9]{2})es una expresión regular con tres grupos de captura, como sigue: 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 que contiene 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);\

Esto (?:/.+)garantiza que la ruta tenga un componente posterior, por lo que ignora cualquier cosa sin un elemento secundario en el directorio principal que son archivos.

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