Solución:
Aquí hay un poco de un delineador que hará lo que quieras:
$ mkdir -p output/{A..Z}; for i in tstdir/*; do export FILE=$(basename "$i"); LTR=$(echo" ${FILE:0:1}" | tr [a-z] [A-Z]); mv "$i" "output/$LTR/$FILE" ; done
Aquí está el mismo comando en forma expandida para que pueda ver lo que está sucediendo:
$ mkdir -p output/{A..Z}
$ for i in tstdir/*; do
FILE=$(basename "$i")
LTR=$(echo "${FILE:0:1}" | tr [a-z] [A-Z])
mv "$i" "output/$LTR/$FILE"
done
Detalles
Lo anterior primero asume que el directorio de salida de solo las letras no existe y, por lo tanto, lo creará,
$ mkdir -p output/{A..Z}
los for
El bucle funciona de la siguiente manera, recorriendo todos los archivos en tstdir/*
. Luego determina el basename
de esta ruta y la almacena en la variable, $FILE
. Cada iteración a través del bucle se almacena en la variable $i
.
FILE=$(basename "$i")
Luego usamos la capacidad de Bashes para devolver el primer carácter de la variable nombrada, $FILE
, y luego usa tr
para convertir cualquier carácter en minúsculas en mayúsculas.
LTR=$(echo "${FILE:0:1}" | tr [a-z] [A-Z])
Desglosando esto un poco más:
$ echo "${FILE:0:1}"
s
$ echo "${FILE:0:1}"
T
Con el tr
código ahora puede ver lo que está pasando:
$ echo "${FILE:0:1}" | tr [a-z] [A-Z]
S
$ echo "${FILE:0:1}" | tr [a-z] [A-Z]
T
El resto del comando simplemente mueve los archivos a su directorio de primera letra correspondiente.
Ejemplo
Digamos que tenemos este directorio de archivos:
$ touch {a-z}file {A-Z}file
$ tree tstdir/ | head -10
tstdir/
|-- afile
|-- Afile
|-- bfile
|-- Bfile
|-- cfile
|-- Cfile
|-- dfile
|-- Dfile
|-- efile
...
Después de ejecutar un trazador de líneas:
$ tree output/ | head -10
output/
|-- A
| |-- afile
| `-- Afile
|-- B
| |-- bfile
| `-- Bfile
|-- C
| |-- cfile
| `-- Cfile
...
Con zsh
mkmv() {mkdir -p -- $argv[-1]:h && mv "[email protected]"}
autoload zmv
zmodload zsh/files
zmv -Qp mkmv '(?)*(^-/)' '${(U)1}/$f'
-
zmv
una función para cambiar el nombre de los archivos por lotes de forma segura utilizando los potentes operadores de expansión y coincidencia de patrones de zsh como una función de carga automática. -
mkmv
: una función que actúa comomv
excepto que también crea el directorio padre del destino si es necesario. -
$argv[-1]
:$argv
igual que$*
es la lista de parámetros posicionales,$argv[-1]
es el último. Aquí, igual que$3
comozmv
lo llama comomkmv -- source destination
-
$var:h
: como encsh
, obtiene el cabeza de la variable, ese es el nombre del directorio. -
zmodload zsh/files
: carga un módulo que habilita la versión incorporada de algunas utilidades de manejo de archivos que incluyenmkdir
ymv
, aquí brindando una mejora significativa en el rendimiento, ya que llamamos a ambos para cada archivo. -
-Q
: habilitar desnudo calificadores glob en el patrón. Estos días, otra opción es reescribir(^-/)
como(#q^-/)
. -
-p mkmv
, contarzmv
para usar nuestromkmv
funcionar como el programa para hacer el cambio de nombre en lugar demv
-
(?)*(^-/)
: un patrón(?)*
con un calificador glob utilizado para hacer coincidir los archivos a renombrar. los?
(para que coincida con un solo carácter) entre paréntesis es capturado por lo que puede denominarse$1
en el reemplazo. -
(^-/)
: calificadores glob utilizados para hacer coincidir archivos en función de más criterios que solo su nombre:-
^
: niega los siguientes calificadores -
-
: para los siguientes calificadores, para los enlaces simbólicos, considere el atributo del destino del enlace en lugar del enlace en sí. -
/
: seleccione archivos de tipo directorio. Con los dos calificadores anteriores, eso significa que queremos archivos que no sean directorios ni enlaces simbólicos a directorios.
-
-
${(U)1}
: el primer carácter capturado del archivo coincidente, convertido a mayúsculas con laU
bandera de expansión de parámetros -
$f
en el reemplazo se refiere a la ruta completa del archivo coincidente.
Prueba con este script:
for first in $(ls -1 | sed 's/^(.).*$/1/' | tr '[a-z0-9]' '[A-Z0-9]' | uniq)
do
mkdir tmp
mv "$first"* tmp/
lower=$(echo $first | tr '[A-Z]' '[a-z]')
mv "$lower"* tmp/
mv tmp/ "$first";
done
La logica es como sigue:
- Enumere todos los archivos del directorio actual.
- Extrae el primer carácter con
sed
. - Cambie el primer carácter a minúsculas con
tr
, esto es para reducir el número de comparaciones. - Eliminar duplicados con
uniq
. - Cree un directorio temporal y mueva todos los archivos que comienzan con el personaje a esta carpeta.
- Cambie el nombre del archivo temporal.
Usé estos archivos para probar el script:
Apple.txt
avocado.txt
banana.txt
broccoli.txt
car.txt
dddd.txt
delete.txt
zaad.txt
zdfa.txt
Aquí está el resultado:
.
├── A
│ ├── Apple.txt
│ └── avocado.txt
├── B
│ ├── banana.txt
│ └── broccoli.txt
├── C
│ └── car.txt
├── D
│ ├── dddd.txt
│ └── delete.txt
└── Z
├── zaad.txt
└── zdfa.txt
5 directories, 10 files