¿Cómo crear dinámicamente la estructura del directorio de destino cuando se usa mv con comodines en bash?

1

Soy bastante nuevo en BASH scripting y estoy buscando una forma elegante de resolver mi tarea:

En un directorio determinado, ciertos archivos deben clasificarse regularmente en subcarpetas. El nombre de los archivos tiene una estructura fija y la carpeta de destino en la que se colocarán esos archivos, depende de sus nombres.

En este momento mis guiones se ven así:

#!/bin/bash
declare -r SOURCEDIR=/some/dir/upload
declare -r DESTBASEDIR=/some/dir/archive

for year in "2009" "2010" "2011" "2012" "2013" "2014"; do
  for letter in {0..9} {A..Z}; do
      mkdir -p ${DESTBASEDIR}/${year}/${letter}
      mv ${SOURCEDIR}/123456789012_${letter}?_??_${year}????.dat ${DESTBASEDIR}/${year}/${letter}/
  done
done

El script hace exactamente lo que quiero, pero crea carpetas de destino incluso si mv no encuentra ningún archivo para moverlo allí. Me gustaría un mv con una opción para crear los directorios necesarios en lugar de crearlos usando mkdir.

Sé que este script mostrará errores cuando no exista ningún archivo para mover. Suprimiré los mensajes de error, cuando se complete el script.

¿Existe una manera fácil y elegante de crear la estructura de directorios sobre la marcha sin crear directores enpty?

¡Gracias por tu ayuda!

Saludos

Manuel


La versión de glenn jackman me inspiró a los siguientes guiones que hacen el truco :)

#!/bin/bash
declare -r SOURCEDIR=/some/dir/upload
declare -r DESTBASEDIR=/some/dir/archive

cd "$SOURCEDIR"
for f in 1234567890_* ; do
  letter=${f:11:1}
  year=${f:21:4}

  dest="$DESTBASEDIR/$year/$letter"

  mkdir -p "$dest"
  mv "$f" "$dest"
done

Tenga en cuenta que las compensaciones dentro del nombre de archivo se han movido desde que descubrí que el número inicial al principio del nombre de archivo es más corto. La solución dada fue diseñada en mi ejemplo falso.

Este enfoque es menos seguro, ya que no se comprueba si los nombres de archivo de los archivos en el directorio de origen están compuestos como se supone. En este caso, puedo confiar en eso, así que no me arriesgo mucho al no verificar esto.

La línea dada en la versión de glenn jackman.

for f in 123456789012_[A-Z]?_??_[0-9][0-9][0-9][0-9]????.dat ; do

no funciono El valor después de "in" se ha interpretado como una cadena literal en mi bash. No sé cómo "reparar" esto.

Manuel
fuente

Respuestas:

1

Esto solo creará los directorios de año / letra que realmente se usan en los nombres de archivo.

cd "$SOURCEDIR"
for f in 123456789012_[A-Z]?_??_[0-9][0-9][0-9][0-9]????.dat ; do
    letter=${f:13:1}
    year=${f:19:4}
    dest="$DESTBASEDIR/$year/$letter"
    mkdir -p "$dest"
    mv "$f" "$dest"
done

Tenga en cuenta que utilizando ${braces} no es lo mismo que usar "$quotes" si el valor de la variable contiene espacios en blanco

glenn jackman
fuente
¡Gracias! Este es un enfoque interesante :) Pero: no hace el truco. Ha olvidado los dígitos en "para la letra en {0..9} {A..Z}; do" y no estoy seguro, cómo agregarlos a su versión.
Manuel