A modo de proyecto para este curso, decidí copiar la idea del profesor de un script que ordenar todos los screen shots en carpetas respecto a cuando fueron creados.
Mi primer idea de solución lo dibuje en el siguiente diagrama.
El primer paso es determinar los meses en que los archivos fueron creados, para ello use:
ls -l
Resultado :
..
-rw-r--r--@ 1 johan staff 104354 29 Aug 12:15 WhatsApp Image 2019-08-29 at 12.14.52 PM.jpeg
-rw-r--r--@ 1 johan staff 23758 24 Jul 10:14 switch.png
drwxr-xr-x 2 johan staff 64 17 Oct 21:05 test
-rw-r-x-w-@ 1 johan staff 0 17 Oct 20:22 text.txt
Luego con grep
y una expresión regularfiltro solo archivos, mi idea es que si el resultado del ls -l
no comienza por con ‘-’ no lo tomo. Y la defino de la siguiente manera:
ls -l | grep "^-.*$"
Resultado:
..
-rw-r--r--@ 1 johan staff 104354 29 Aug 12:15 WhatsApp Image 2019-08-29 at 12.14.52 PM.jpeg
-rw-r--r--@ 1 johan staff 23758 24 Jul 10:14 switch.png
-rw-r-x-w-@ 1 johan staff 0 17 Oct 20:22 text.txt
Luego con awk
y un print
filtro los meses en que los archivos cuando fueron creados. En este link encontré una forma de hacerlo.
ls -l | grep "^-.*$" | awk '{print $7}'
Resultado:
..
Sep
Sep
Oct
Oct
Oct
Jul
Sep
Sep
Sep
Sep
Aug
Jul
Oct
..
Luego para filtrar todos los archivos repetidos con sort -u
puedo hacerlo. De este link tome la idea:
ls -l | grep "^-.*$" | awk '{print $7}' | sort -u
Y para guardar el resultado de este comando en una variable de bash en este link que se hace así:
MONTHS=$(ls -l | grep "^-.*$" | awk '{print $7}' | sort -u)
Y además cree este comando para determinar el año de creación de los archivos:
YEAR=$(date | awk '{print $4}')
Para formalizar el script cree un archivo llamado “sort_screen_shots.sh” y hasta este punto se ve así :
#!/bin/bash
MONTHS=$(ls -l | grep "^-.*$" | awk '{print $7}' | sort -u)
YEAR=$(date | awk '{print $4}')
<h3>Paso 2:</h3>
El segundo paso es la creación de las carpetas donde se van a ordenar los archivos, para ello use un ciclo for
el cual es muy parecido al de Python, acá encontré como se define. Y aplicado a mi proyecto se ve de la siguiente manera:
#!/bin/bash
MONTHS=$(ls -l | grep "^-.*$" | awk '{print $7}' | sort -u)
YEAR=$(date | awk '{print $4}')
for i in$MONTHSdo
mkdir -pv "$i-$YEAR"done
Resultado:
Aug-2019
Jul-2019
Oct-2019
Sep-2019
El -p
e es para que si la carpeta ya esta no genere error y el -v
es para que muestre en terminal lo que esta creando.
El tercer paso es mover los archivos a sus carpetas respectivas. Para ello dentro del ciclo for
aplique una expresión regular que filtrara los archivos que fueron creados en ese respectivo mes y luego con awk
tomo los nombres para moverlos a las carpetas. El script se ve de la siguiente manera.
#!/bin/bash
MONTHS=$(ls -l | grep "^-.*$" | awk '{print $7}' | sort -u)
YEAR=$(date | awk '{print $4}')
for i in$MONTHSdo
mkdir -p $i-$YEAR
REGEX="^-.*\s${i}\s\d\d:\d\d.*$"
FILES_TO_MOVE=$(ls -l | grep $REGEX | awk '{print $9}')
mv -v $FILES_TO_MOVE$i-$YEAR/
done
Donde la expresión regular se puede entender de la siguiente manera:
Si no entendiste la expresiones regular te invito a hacer el curso de Regex (Excelente curso!)
Pero el script aún tiene un error, por que los nombres se generan con espacios en MacOs , entonces awk
nos retorna solo la primera parte del nombre de los archivos y con esto comando mv
genera problemas. Buscando por internet varias formas de solucionar esto 1, 2, pero creo la mejor solución seria cambiar los " " por “_” en los nombres y así lo implemente:
# rename filesfor f in"$(ls | grep '\s')"do
mv "$f""${f// /_}"done
Esta idea la tome de este foro y muestra una funcionalida de bash llamada “Parameter expansion” (MUY Interesante).
Y al final mi scrip quedo de la siguiente manera:
Versión final:
#!/bin/bash# path of the screen shots folder
PATH_SCREEN_SHOT="$HOME/Documents/screen-shots"
SORT_DATE=$(date)
echo"Date of sort $SORT_DATE"# move to the main pathecho"move to $PATH_SCREEN_SHOT"cd$PATH_SCREEN_SHOT# rename filesfor f in"$(ls | grep '\s')"doif [ -n "$f" ]
then
mv -v "$f""${f// /_}"fidone# move files
MONTHS=$(ls -l | grep '^-.*$' | awk '{print $7}' | sort -u)
YEAR=$(date | awk '{print $4}' )
echo'Beginning To Move'for i in$MONTHSdoif [ -n "$i" ]
then
mkdir -pv $i-$YEAR
REGEX="^-.*\s${i}\s\d\d:\d\d.*$"
FILES_TO_MOVE=$(ls -l | grep $REGEX | awk '{print $9}')
mv -v $FILES_TO_MOVE$i-$YEAR/
fidone
Agregue un if
en cada for
para evitar problemas cuando no se encuentren archivos el script no genere errores, además echo
y -v
para crear un “.log” de la ejecución.
El cuarto paso es agregar el script al crontap, esto lo hacemos atraves de el comando crontab -e
y creamos nuestra configuración de días de ejecución cómo en la clase lo mostraron.
0 0 */15 * * /Users/johan/.my_crontap_scripts/sort_screen_shots.sh > /Users/johan/.my_crontap_scripts/sort.log
<h3>Lecciones aprendidas</h3>
Antes de hacer este mini-proyecto pensaba que era algo sencillo que con mi experiencia en Linux (4 años usando Ubuntu) no me tomaría mas de una tarde, pero me tomo 5 días con un promedio de tres horas de trabajo por día. Pero valió el tiempo invertido por que aprendí muchísimo en el procesó. Si sabes una forma mas sencilla de solucionar esté problema déjenme lo saber en los comentarios o Twitter . Gracias por leer este post 🤙🏾.
<h3>Referencias</h3>
useful link related to this https://speedysense.com/bash-if-else-statement/