¿Cómo mover cada archivo de una carpeta a un subdirectorio con el mismo nombre?

¿Cómo mover cada archivo de una carpeta a un subdirectorio con el mismo nombre?

Digamos que tengo un montón de archivos en un directorio.

filename-1.ext1
filename-1.ext2
filename-1.ext3
filename-2.ext1
filename-2.ext2
filename-2.ext3
filename-3.ext1
filename-3.ext2
filename-3.ext3

Luego quiero crear subdirectorios en el mismo directorio con el mismo nombre que los archivos (nombre de archivo pero sin extensión) y moverlos así

filename-1
├──filename-1.ext1
├──filename-1.ext2
└──filename-1.ext3
filename-2
├──filename-2.ext1
├──filename-2.ext2
└──filename-2.ext3
filename-3
├──filename-3.ext1
├──filename-3.ext2
└──filename-3.ext3

¿Cuál sería la forma más eficiente de lograr esto?

Editar: ext1, ext2, ext3 son solo para indicar tres nombres de archivos distintos, como .foo, .bar, .top, .coffee, etc. No es que los nombres de archivos sean similares.

Respuesta1

Como estás usando zsh, esto podría hacerse así:

for name (*.ext<->(.)) mkdir -p -- $name:r && mv -- $name $name:r 

o usando la forma larga más familiar del forbucle,

for name in *.ext<->(.); do
    mkdir -p -- $name:r &&
    mv -- $name $name:r
done

Esto itera sobre todos los archivos normales que coinciden con el patrón *.ext<->donde <->coinciden con cualquier número. Es el calificador global (.)que impone la coincidencia sólo de archivos normales. Cambie todo el patrón *.*(.)si desea que coincida con el nombre de cualquier archivo normal que contenga un punto; Requerimos que el punto esté presente ya que desea eliminar una extensión de nombre de archivo más adelante. Para utilizar un patrón más estricto en lugar de más flexible, utilice algo como filename-<->.ext<->(.). Este patrón requiere que sepas que deseas hacer coincidir nombres que comiencen con la cadena filename-.

La $name:rexpansión dará como resultado el mismo valor que $name, pero sin la extensión (es decir, sólo la "raíz" del valor).

Se utiliza --para señalar el final de las opciones a ambos mkdiry mvevitar que los nombres que comienzan con un guión se confundan con opciones.

Respuesta2

Con zmv:

autoload -Uz zmv # best in ~/.zshrc
mkmv() { mkdir -p -- $2:h && mv -- "$@"; }

zmv -P mkmv -n '(*).ext<->(#q.)' '$1/$f'

(eliminar -ncuando esté satisfecho).

De esa manera, se beneficiará de zmvlos controles de cordura de.

Respuesta3

Utilice este forbucle que es compatible con los shells bash y zsh:

for file in *.*; do
  [ -f "$file" ] &&
    mkdir -p -- "${file%.*}" &&
    mv -- "$file" "${file%.*}/"
done
  • -pLa opción en mkdirse asegura de que el archivo exista no genera un error.
  • %.*elimina la extensión de los nombres de archivos.

Respuesta4

Con GNU paralelo (una herramienta de la que recién estoy empezando a darme cuenta del poder):

ls | parallel 'mkdir -p {.}; mv -i {} {.}'

Como esto no está vinculado a la CPU de ninguna manera, supongo que parallelno brindará ninguna ventaja de velocidad, pero aún así es más corto que muchas de las otras soluciones dadas.

Y esto no depende del patrón de nombres de archivos.

información relacionada