¿Cómo reemplazar una carpeta cuyo nombre es una fecha, es decir, AAAAMMDD con una jerarquía de carpetas del año, el mes, la 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 que va de año en mes, y mover los documentos de texto a la carpeta correspondiente de 'fecha' 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 cree subcarpetas nombradas con meses como 01, y luego cree más subcarpetas nombradas con fechas como 29 que contienen el documentos de texto correspondientes.

Por lo tanto, la ruta se vería como 2015/01/29/file.txt o 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 pueda comprender cualquier persona que no sepa cómo hacerlo, 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 solucionaría este problema siempre que haya una solución?

pregunta davidjnatarajan 29.04.2017 - 17:22

2 respuestas

8

Suponiendo que todas estas carpetas YYYYMMDD forman 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 bucle for d in */; do lee todas las entradas del directorio, el / final garantiza que solo los nombres de los directorios coincidan realmente
  • [[ $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 de bash para crear una cadena que contenga la nueva ruta
  • El -- en mkdir y mv evita problemas en caso de que el directorio o nombre de archivo comience con un - . Esto no puede suceder aquí, pero probablemente sea una buena práctica de todos modos.

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

    
respondido por el nohillside 29.04.2017 - 20:12
8

Puedes usar lo siguiente en la Terminal. cd a 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);\
  mkdir -p -- $(dirname "$F");\
  mv -- "$1" "$F"' - {} \;

find . -type f obtiene recursivamente todos los archivos del directorio actual.
-exec bash -c abre 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, de la siguiente manera:
//esreemplazo,dondecadagrupodecaptura(,etc.)estáseparadopor/.
mkdir-p--$(dirname"$F") crea los directorios para mover los archivos.
mv -- "$1" "$F" mueve cada archivo a su carpeta correspondiente.

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);\

El (?:/.+) garantiza que la ruta tenga un componente posterior, por lo tanto, ignorando cualquier cosa sin un hijo en el directorio principal, que son archivos.

    
respondido por el grg 29.04.2017 - 18:16

Lea otras preguntas en las etiquetas