
Dados muchos directorios/subdirectorios que contienen muchos tipos de archivos diferentes (csv, txt, jpg, etc.), ¿qué comando buscará en cada directorio de forma recursiva y copiará los archivos en un nuevo directorio de nivel superior con el nombre de cada extensión?
¿Hay alguna manera de lograr esto con una sola línea?
Respuesta1
Solución
El siguiente comando enumerará todos los archivos en el directorio actual ( .
) y los moverá a directorios con el nombre de sus extensiones en ./OUTPUT
:
for file in $(find . -type f) ; do EXTENSION=$(echo "$file" |sed 's/.*\.//g') ; rsync -av $file ./OUTPUT/$EXTENSION/ ; done
Antes de ejecutar el comando anterior, deberá:
- Cree el directorio OUTPUT en el directorio actual (
mkdir OUTPUT
) - Asegúrese de que no haya archivos con nombres coincidentes en ninguno de los subdirectorios
Explicación
En primer lugar, el bucle asigna a la variable file
un archivo de la salida de find . -type f
. A continuación se muestra un ejemplo de salida del find
comando:
./a/myfile1.zip
./a/b/adoc1.txt
./a/b/adoc2.txt
./a/b/adoc3.txt
./a/b/adoc4.txt
./a/myfile3.zip
./a/myfile4.zip
./a/myfile2.zip
La variable EXTENSION
se crea y su valor es la file
variable con todo hasta el último punto eliminado. Así ./a/myfile1.zip
sería zip
.
Luego, el archivo se sincroniza (con detalle, v
) con un directorio que lleva OUTPUT
el nombre de la extensión del archivo.
Un ejemplo de mi árbol de archivos después de ejecutar este comando en alguna prueba:
./a
./a/b
./a/b/adoc1.txt
./a/b/adoc2.txt
./a/b/adoc3.txt
./a/b/adoc4.txt
./a/b/c
./a/myfile1.zip
./a/myfile2.zip
./a/myfile3.zip
./a/myfile4.zip
./b
./b/c
./b/c/d
./b/c/file1.txt
./b/c/file2.txt
./b/c/file3.txt
./b/c/file4.txt
./c
./c/d
./c/d/e
./c/d/e/afile1.rar
./c/d/e/afile2.rar
./c/d/e/afile3.rar
./c/d/e/afile4.rar
./OUTPUT
./OUTPUT/rar
./OUTPUT/rar/afile1.rar
./OUTPUT/rar/afile2.rar
./OUTPUT/rar/afile3.rar
./OUTPUT/rar/afile4.rar
./OUTPUT/txt
./OUTPUT/txt/adoc1.txt
./OUTPUT/txt/adoc2.txt
./OUTPUT/txt/adoc3.txt
./OUTPUT/txt/adoc4.txt
./OUTPUT/txt/file1.txt
./OUTPUT/txt/file2.txt
./OUTPUT/txt/file3.txt
./OUTPUT/txt/file4.txt
./OUTPUT/zip
./OUTPUT/zip/myfile1.zip
./OUTPUT/zip/myfile2.zip
./OUTPUT/zip/myfile3.zip
./OUTPUT/zip/myfile4.zip
Respuesta2
Esto se puede hacer de forma muy sencilla conencontrar, como lo sugirió correctamente Alex: asumiendo que el directorio para buscar archivos es/ruta1/a/algún/diry desea mover los archivos a/ruta2/a/otro/dir/txtetcétera,
find /path1/some/dir -type f -exec bash -c 'MYDIR=/path2/to/other/dir${0##*.}; [ -d $MYDIR ] && mv $0 $MYDIR || mv $0 /path3/to/miscellanea' {} \;
Este comando primero busca todos los archivos (-tipo f) contenido dentro del directorio/ruta1/a/algún/diry todos sus subdirectorios, luego pasa el nombre de cada uno de esos archivos ({}) a un pequeño bash de dos líneas, que primero extrae la extensión del nombre del archivo (denominado$0dentro de bash) y lo asigna a la variable de shell localMYDIR, entoncespruebaspara la existencia de un directorio adecuado (si no existe dicho directorio, entonces tal vez cometimos un error), y si el directorio existe (&&...) mueve el archivo al directorio apropiado; de lo contrario (||...) coloca el archivo en un lugar predeterminado,/ruta3/a/miscelánea.
Lo anterior supone que ya ha creado los directorios necesarios,/ruta2/a/otro/dir/txtetcétera. Si por el contrario deseas crearlos sobre la marcha, tendrás que modificar lo anterior como:
find /path1/some/dir -type f -exec bash -c 'MYDIR=/path2/to/other/dir/${0##*.}; mkdir -p $MYDIR && mv $0 $MYDIR' {} \;