DIY Tasker. Parte 1

DIY. Hazlo tu mismo 20 de may. de 2025

DIY Tasker. Hazlo tu mismo

Os comenté en el artículo anterior que en vez de daros directamente el código de TASKer mi gestor de tareas, lo que vamos a hacer es ver como lo he programado en bash, en una especie de curso-tutorial para que podais contruir el vuestro propio.

Ventajas:

  • Aprenderás de verdad a pelearte con un script en bash al tener que programarlo y entender la lógica y comandos que se usan.
  • Verás cosas que no funcionan (y explicaremos porqué) y cual es una solución (mi solución) al problema.
  • Puedes adaptarlo a tus necesidades y gustos.
  • Si eres nuevo en el scripting, verás algunos trucos o métodos diferentes en la programación bash
  • Estarás orgulloso de haber programado tu propia aplicación.
  • El propio script es una especie de resumen de trucos de comandos y operaciones en bash que os puede servir en el futuro para otras tareas.

Desventajas:

  • Hasta el último artículo no disponeis de una versión totalmente operativa, salvo que vayais avanzando por vuestra cuenta en la programación de la aplicación.

Analizando TASKer

Empecemos por lo primero de todo, explicando qué es y qué no es , que podemos esperar del programa, cual es el producto minimo viable para considerarlo funcional, que mejoras podemos incluirle, etc...

¿Qué es TASKer?

TASKer es un script desarrollado en bash para gestionar desde la terminal las tareas personales o las tareas de un grupo de trabajo de una forma simplificada siguiente un esquema similar al "Cuadrante de Eisenhower".

Qué no es TASKer

No es una aplicación profesional, ni sigue una metodología de gestión de tareas o grupos.
No es una aplicación gráfica.

Que podemos esperar de TASKer

Se trata de una herramienta para la terminal, de uso rápido que permita anotar tareas, organizarlas y posteriormente repartirlas entre los miembros de un grupo de trabajo.

Tiene que funcionar el cualquier terminal que use bash: cualquier PC con GNU/Linux, PC con WSL, o incluso un Móvil o Tablet con Termux.

Tiene que ser fácil de leer su código, modificarlo y adaptarlo a las necesidades personales de cada uno.

Producto Mínimo Viable (MVP de TASKer)

Para que consideremos que la aplicación es operativa y podamos comenzar a usarla, TASKer debe de poder realizar lo siguiente:

  • Capturar y almacenar nuevas Tareas
  • Organizar/mover las tareas recibidas a los apartados o cuadrantes que deseemos
  • Repartir las tareas de los cuadrantes a los miembros del grupo
  • Permitir marcar como "cerrada" cualquier tarea
  • Listar todas las tareas y su estado.

Mejoras que podemos incluir en Tasker

Algunas mejoras las abordaremos durante la realización de este curso-tutorial, otras las dejaremos para mejoras futuras

  • Aspecto visual, colores, logotipo de la aplicación.
  • Tareas en formato Markdown.
  • Generacion en formato PDF de las Tareas.
  • Estadística de las Tareas.
  • Otras que puedan surgir en la programación...

Comenzamos...

Con todo lo anterior en mente, debemos pensar en cómo vamos a trabajar con nuestro código.

Protegiendo nuestro código

Lo primero que te recomiendo es que programes usando Git.

Git es un sistema de control de versiones que realiza un seguimiento de los cambios en los archivos.

De esta forma ante cualquier problema, error o borrado de tu código puedes volver a una versión previa del mismo.

Puedes ir escribiendo el código desde cualquier sitio, desde tu PC de sobremesa, tu portatil o incluso desde una Tablet con Termux. luego sólo tienes que subir el código al repositorio git y lo tendras disponible desde cualquier sitio.

Para entender qué es GIT, te recomiendo leer el artículo:

Entender Git en minutos
Aprender Git en minutos con ejemplos

Entender Git en minutos

Editor para el código

Puedes usar cualquier editor de texto con el que te sientas cómodo.

Si lo vas a programar desde la terminal te recomiendo usar Vi/Vim, lo tienes disponible en cualquier versión de Linux, puedes leer un artículo sobre Vim para aprender como usarlo:

VIM
El temido, odiado y amado editor Linux VIM: Vim (Vi Mejorado) es una versión del editor de texto Vi, presente en todos los sistemas UNIX. Hoy en día está de moda entre las nuevas generaciones el uso de Sublime Text, VsCode o Atom. Sin embargo estas aplicaciones modernas tienen una

https://soloconlinux.org.es/vim/

Si vas a trabajar en un equipo que disponga de escritorio gráfico, te recomiendo usar VS Codium la es versión de VS Code de Microsoft pero sin el tracking/seguimiento.

Visual Studio Code y VSCodium
Visual Studio Code (VSCode) versus VSCodium Si eres desarrollador seguramente quieras usar Visual Studio Code. Existe una versión idéntica, pero a la que se ha eliminado la telemetría (información que se envía a Microsoft cada vez que usas su programa) ese programa es VSCodium. Instalación de Visual Studio Code Abre

https://soloconlinux.org.es/visual-studio-code-y-vscodium/

Curiosidades sobre TASKer: En mi caso, el 90% del código de la aplicación la he programado en los trayectos realizados en Cercanías, todo ello escritor usando Vim, desde la terminal en una Tablet Android en la que tengo instalado Termux.

Si además quieres aumentar tu productividad y comodidad, puedes instalar Tmux en la Tablet para trabajar en modo multi-ventana desde un único terminal.

Programando en pantalla divida con Tmux en Tablet ejecutando Termux

Puedes aprender a usar Tmux para sacarle todo el provecho leyento el siguiente artículo artículo:

TMUX
Multiplexor de Ventanas tmux es un multiplexor de terminal para sistemas tipo Unix/Linux, similar a los pogramas GNU Screen o Byobu que permite dividir una consola en múltiples secciones ya sea en modo horizontal, vertical o combinaciones de ellas. Además te permite generar sesiones independientes en la

https://soloconlinux.org.es/tmux/

Vamos con la Idea

Antes de ponerme con el desarrollo, necesito un esquema previo de los procesos mínimos y que pasa en ellos para luego poder pasar ese esquema a una primera version de código....

borrador de los procesos de la aplicación

Básicamente obtengo los siguientes procesos de entrada y salida para cada acción del programa:

  • Alta de Tareas:
    - Entrada: Cualquier tipo de tarea que pueda surgir o recibir, ya sea por email, chat, videoconferencia, gestor de incidencias o teléfono, tengo que poder capturarla con el teclado de forma muy rápida.
    - Salida: Se crea el fichero entrada y se almacena en él la fecha y el texto de la tarea de forma secuencial en texto sin formato.
  • Organizar Tareas:
    - Entrada: Se muestra linea a linea el fichero entrada y se captura las teclas D, S, U y F para repartir en el cuadrante de Tareas DSUF (Diaria/Semanal/Urgente/Futuras)
    - Salida: Cuatro ficheros dia, semana, urgentes y futuras las tareas organizadas desaparecen del fichero entrada
  • Repartir Tareas:
    - Entrada: Usaremos un fichero auxiliar grupo del que obtengo los miembros del grupo y su letra rápida para repartir cada una de las tareas de cada fichero DSUF.
    - Salida: Se modifica cada fichero dia, semana, urgentes y futuras y se incluye al miembro encargado de resolver esa tarea.
  • Cerrar Tareas:
    - Entrada: Se recorren todos los ficheros DSUF y sus tareas. Se captura la tecla C si se quiere marcar cada tarea como cerrada.
    - Salida: Se modifica cada fichero dia, semana, urgentes y futuras y se incluye [X] para tareas cerrada y se deja como [ ] para tareas sin cerrar.
  • Ver Tareas:
    - Entrada: Se leen los ficheros DSUF y se muestra el contenido de cada fichero forma paginada.
    - Salida: No se generan ficheros.

Codificando

Para tener una mayor claridad y separar código vamos a crear un directorio al que llamaremos lib que usaremos a modo de almacen de las "librerías y funciones de nuestro código":

Crearemos el directorio necesario:

mkdir -p lib

La estructura quedará así:


directorio_TASKer/
└── lib

Nuestro primer fichero que va a ir dentro del directorio lib va a ser un fichero en el que pongamos todas las variables que vamos a usar en nuestro programa.
Le vamos a llamar Tvariables para abreviar Tasker + variables

Creamos el fichero simplemente con el comando touch lib/Tvariables y lo editamos para incluir por ejemplo la siguiente variable globales, para poder definir el nombre del fichero de entrada en que guardaremos las tareas nuevas:

# FICHERO DE VARIABLES GLOBALES DE LA APLICACION

# Para ficheros
FE="TASKer.Entrada"
Nota: si no te gusta el nombre del fichero, simplemente cambia el nombre del fichero por el tuyo personalizado.

Ahora creamos el programa principal, al que yo voy a llamar TASKer simplemente creamos el fichero, le damos permisos de ejecución.

touch TASKer
chmod +x TASKer

Luego lo editamos e incluimos el siguiente código:

#!/bin/bash
# Incluir variables
. lib/Tvariables
Truco: Includes en Bash

En vez de tener en el código principal del programa todas las variables que voy a necesitar, que pueden ser muchas y me darían un código final poco legible, las dejo en un fichero externo y las cargo/incluyo en la ejecución del código del programa principal.

Puedes leer la explicación de esto en el artículo de mi blog:

Include en scripts Bash
¿Includes en Bash? Seguro que te sorprende, pero en un script bash puedes realizar “includes” como si de un lenguaje de alto nivel se tratase. Tienes al menos dos formas de realizar la inclusión de código externo a tu script bash: * . /ruta/fichero * source /ruta/fichero Que diferencias hay entre

Includes en bash

Editamos el script TASKer e incluimos algo más de código para depurar que es correcto y se leen las variables mediante el include:

#!/bin/bash
# Incluir variables
. lib/Tvariables

# Depuracion - borrar despues
echo "El fichero de entrada es: $FE"

Lo ejecutamos escribiendo en la terminal: ./TASKer

Y comprobamos que efectivamente ha leido el valor del fichero externo de variables:

./TASKer 

El fichero de entrada es: TASKer.Entrada
Truco: No es necesario la extensión.

Te abrás dado cuenta que al script bash no le he incluido la extensión .sh y Linux lo sabe ejecutar correctamente.

En Linux se sigue la máxima de "El hábito no hace al monje".
Al igual que el refrán, se recomienda no juzgar por su aspecto externo, pues no siempre el exterior corresponde al interior.

En Linux/Unix se usa Shebang, que en la jerga linuxera, es el nombre que recibe el par de caracteres #! que se encuentran al inicio de los programas ejecutables que son interpretados. También lo puedes encontrar con el nombre de hash-bang o sharpbang.
Estos caracteres indican al intérprete de comandos que programa es necesario para ejecutar el código interno del programa.

El nombrar al script como TASKer en vez de TASKer.sh le da un toque más profesional 🧑🏻‍💻

Logotipo

Antes de ponernos a tope con el código, el disponer de un logo para el programa hace que luzca más profesiónal, es un capricho chulo que nos vamos a permitir para que cada vez que lancemos una prueba inicial veamos lo bonito que va a quedar....

Podemos hacer mediante ASCII-Art nuestro propio logotipo o usar algun comando Linux que nos simplifiquen el proceso.
Disponemos de 3 aplicaciones básicas que nos permiten hacer Arte ASCII de forma sencilla:

  • banner: Puedes instalarlo mediante sudo apt -y install sysvbanner
  • toilet ó figlet: Puedes instalarlo con el comando sudo apt -y install toilet

Uso y resultado de cada uno de ellos:

$ banner TASKer


#######    #     #####  #    #
   #      # #   #     # #   #    ######  #####
   #     #   #  #       #  #     #       #    #
   #    #     #  #####  ###      #####   #    #
   #    #######       # #  #     #       #####
   #    #     # #     # #   #    #       #   #
   #    #     #  #####  #    #   ######  #    #

figletResultado con "banner"

$ toilet TASKer

                                          
mmmmmmm   mm    mmmm  m    m              
   #      ##   #"   " #  m"   mmm    m mm 
   #     #  #  "#mmm  #m#    #"  #   #"  "
   #     #mm#      "# #  #m  #""""   #    
   #    #    # "mmm#" #   "m "#mm"   #    
                                      

Resultado identico con "figlet" y "toilet"

banner es una aplicación que viene de la época de los Unix System V, de los años 1983, y emula exactamente lo que hacía el código de aquella época, no se le puede pedir más.

Sin embargo toilet / figlet es una aplicación moderna que puede hacer lo mismo que banner y algo más.... así que vamos a aprovecharla para hacer nuestro logo:

toilet -f smblock --filter border:metal TASKer

Como la aplicación es de consola y además debe de ser portable, lo que vamos a hacer es generar el logotipo de la aplicación y almacenarlo para poder usarlo sin tener que disponer del programa toilet en ningun equipo.

Para ello vamos a guardar la salida en un fichero al que por ahora vamos a llamar logo:

toilet -f smblock --filter border:metal TASKer > logo

Si ejecutamos un cat logo veremos que se muestra el logotipo perfectamente.
Sin embargo si abrimos con un editor el fichero logo veremos algo totalmente "extraño":

contenido del fichero "logo"💯i

Esto no es más que un texto en el que los colores se indican mediante caracteres de escape.

Puedes ver el artículo completo en el que te cuento como usar los colores en bash:

Colores en Bash
Porqué usar colores en Bash El mostrar colores en la salida de la ejecución de comandos, facilita mucho la lectura o localización de una forma más sencilla la salida de la ejecución de un script que hayamos desarrollado para ejecutar en Linux. Colores disponibles Un ejemplo de salida de colores

Colores en bash

Lo que vamos a hacer es guardar todo este conjunto de caracteres de texto como una variable en nuestro fichero de variables Tvariables, lo vamos a hacer de una forma sencilla:

echo 'LOGOTIPO="' >> lib/Tvariables
toilet -f smblock --filter border:metal TASKer >> lib/Tvariables
echo '"' >> lib/Tvariables

Incluir variable LOGOTIPO

Nuestro fichero de variables se verá ahora así:


Vamos a crear nuestro primer fichero de Librería TLibPantalla y nuestra primera función Logo() para mostrar a nuestro antojo el logotipo.

touch lib/TLibPantalla

Lo editamos y escribimos

# LIBRERIA DE FUNCIONES PARA DIBUJAR EN PANTALLA

function Pantalla::Logo() {
 clear
 echo -e "$LOGOTIPO"
}
Truco: echo -e

El comando echo permite el modificador -e que permite interpretar los caracteres de escape y en nuestro caso dibujar con colores.

Recuerda además que la función la hemos creado con el nombre Pantalla::Logo y debemos usarla con su nombre completo, hacemos eso simplemente para saber luego en que fichero/librería está cada función.

Modifiquemos el programa principal TASKerpara hacer uso de la librería mediante un include y usar nuestra nueva función:

#!/bin/bash 
# Incluir variables
. lib/Tvariables

# INCLUDES ;-D
. lib/TLibPantalla

# --- Main ---
Pantalla::Logo

Si ejecutamos el programa veremos nuestro logo a todo color y sin necesidad de ningun programa externo para dibujarlo.

El Menú

Vamos a necesitar dibujar un menú para que sepamos que tarea estamos realizando o que tecla hay que pulsar para ejecutar una acción.

Nuestro primera aproximación al menú de la aplicación va a mostrar algo así:

 MENU PRINCIPAL:
 [A] ALTA DE TAREAS
 [O] ORGANIZAR TAREAS
 [R] REPARTIR TAREAS AL GRUPO 
 [C] CERRAR TAREAS
 [V] VER LAS TAREAS 
 [F] FIN DEL PROGRAMA TASKer

Pues vamos a modificar la libreria de pantalla lib/TLibPantalla para incluir la funcion que pinte el menú:

function Pantalla::PintarMenu() {
  echo "MENU PRINCIPAL:
[A] ALTA DE TAREAS
[O] ORGANIZAR TAREAS
[R] REPARTIR TAREAS AL GRUPO 
[C] CERRAR TAREAS
[V] VER LAS TAREAS 
[F] FIN DEL PROGRAMA TASKer
"
}

Vamos a crear en el mismo fichero otra funcion de nombre Menu que va a realizar lo siguiente, se ejecuta en un bucle infinito del que solo sale si se pulsa una de las teclas del menú.

  • Primero muestra el logotipo
  • Despues pinta el menu
  • Espera hasta que se pulsa una tecla correcta

La función del menú quedaría así:

function Pantalla::Menu() {
  while true
  do
    Pantalla::Logo
    Pantalla::PintarMenu
    # Esperamos que pulse una tecla.
    # la pulsacion se guarda en la variable $opcion
    read -n 1 -s -p " -- Pulse inicial de opción -- " opcion
    # Tecla pulsada a MAYUSCULAS
    opcion=$(echo $opcion|tr [:lower:] [:upper:])
    valoresMenu="AORCVF"
    # Comprobamos si la tecla esta en el grupo de teclas permitidas
    valido=$(echo $valoresMenu |grep -c -v "$opcion" -- 2>/dev/null|awk '{print $1}')
    if [ "$valido" == "0" ] 
    then
      # Dejamos salir porque es una Tecla del menu
      break
    else
      # Mensaje en pantalla de error y esperamos 0.75 segundo para que se vea
      echo ""
      echo "** Opcion incorrecta **"
      sleep 0.75
    fi
  done
}

Modificamos el fichero TASKer quedando así:

#!/bin/bash 
# Incluir variables
. lib/Tvariables

# INCLUDES ;-D
. lib/TLibPantalla

# --- Main ---
Pantalla::Menu

Comprobamos su funcionamiento y vemos que se queda ejecutandose en pantalla hasta que pulsemos una de las opciones correctas del menú:

Menú version 1.0

Vamos a darle más importancia a las teclas que se deben de pulsar, vamos a crear una variable Global el valor de la tecla pulsada opcion y además en el menú vamos a "colorear" la teclas que hay que pulsar.

Como seguramente necesitemos estos colores en más partes del programa, vamos a crear unas variables para definir y usar los colores de forma sencilla con el comando echo -e

Al fichero lib/Tvariables le incluimos las siguientes líneas:

....

# Pulsaciones del Menu
opcion=""

# Para Colores en Pantalla
ColorNormal="\e[0m"
Rojo="\e[31m"
RojoIntenso="\e[1;31m"
Verde="\e[32m"
VerdeIntenso="\e[1;32m"
Amarillo="\e[33m"
AmarilloIntenso="\e[1;33m"
Azul="\e[34m"
AzulIntenso="\e[1;34m" 

Y modifico la función PintarMenu para que coloree cada tecla:

function Pantalla::PintarMenu() {
 echo -e "$Azul MENU PRINCIPAL:$ColorNormal
 ["$VerdeIntenso"A"$ColorNormal"] ALTA DE TAREAS
 ["$VerdeIntenso"O"$ColorNormal"] ORGANIZAR TAREAS
 ["$VerdeIntenso"R"$ColorNormal"] REPARTIR TAREAS AL GRUPO
 ["$VerdeIntenso"C"$ColorNormal"] CERRAR TAREAS
 ["$VerdeIntenso"V"$ColorNormal"] VER LAS TAREAS
 ["$VerdeIntenso"F"$ColorNormal"] FIN DEL PROGRAMA TASKer
"
}

Si además modificamos la línea cuando se pulsa una tecla errónea, para que mueste el texto en rojo:

echo -e "    "$Rojo"** Opcion incorrecta **"$ColorNormal"\n"

La nueva versión del menú se ve así:

Menú version 2.0

Alta de Tareas

Vamos a crear nuestra librería para gestionar las tareas mediante funciones para simplificar el código, la vamos a crer también dentro del directorio lib y la vamos a llamar TLibTareas

En esta librería vamos a crear una función para ejecutar una acción dependiendo de la tecla que pulsó anteriormente que tenemos almacenado en la variable global $opcion , esta función se va a llamar Tareas::Accion

# LIBRERIA DE FUNCIONES PARA REALIZAR TAREAS

function Tareas::Accion() {
  case $opcion in
  	A)
      	Tareas::Alta
    		;;
  	O)
      	Tareas::Ordenar
    		;;
  	R)
      	Tareas::Repartir
    		;;
   	C)
      	Tareas::Cerrar
    		;;

  	V)
      	Tareas::Ver
    		;;
  	F)
      	Tareas::Fin
    		;;
  esac
}

Además vamos a crear la función Tareas:Alta que el la función que grabará cada una de las tareas en el fichero de entrada de tareas:

function Tareas::Alta() {
  # Formato: "Y-m-d Texto_de_la_tarea"
  FICH="$FE"
  while true
  do
    Pantalla::PintarPedirAlta
  	read tarea
	if [ "$tarea" == "" ] ; then
	   break
	else
	   echo "$DIA $tarea" | tr [:lower:] [:upper:] >> $FICH
	fi
  done
}

Esta función tiene las siguientes peculiaridades:

  • Se ejecuta en bucle, solo se sale de la función si se pulsa INTRO sin ningún tipo de texto
  • El texto escrito se almacena en la variable $tarea al pulsar INTRO, el texto se guarda en el fichero que indicamos en la variable $FE del fichero TVariables
  • Cada línea de texto escrito se le incluye por delante de él, el día en formato YYYY-MM-DD (año-mes-dia), esto nos servirára posteriormente para realizar busquedas y ordenaciones por fecha de una forma fácil.
  • El valor de $DIA lo vamos a tener definido como una variable en el fichero Tvariables de la siguiente forma:

# Dia / Hora
DIA=$(date +%Y-%m-%d)
  • Pintaremos una pantalla con texto mediante la función PintarPedirAlta para indicar lo que hay que hacer.
    Esta función va en la librería TLibPantalla:
function Pantalla::PintarPedirAlta() {
    Pantalla::Logo
  	echo -e " "$Azul"ESCRIBA LA TAREA + INTRO"$ColorNormal
	  echo -e " (INTRO sin texto para Salir)\n"
}

También vamos a crear la función para finalizar el programa, que es una de las más sencillas y va en la librería TLibTareas:

function Tareas::Fin() {
  clear
  exit 0
}

Por ultimo editamos TASKerel fichero principal de la aplicación para realizar el include de la nueva libreria TLibTareas el código debería ser el siguiente:

#!/bin/bash 
# Incluir variables
. lib/Tvariables

# INCLUDES ;-D
. lib/TLibPantalla
. lib/TLibTareas

# --- Main ---

while true
do
  Pantalla::Menu
  Tareas::Accion
done

Cierto, lo has visto.... otro bucle para que no salgamos del menu...

Si ahora ejecutamos el programa con el comando ./TASKer nos quedamos en el menún de forma indefinida hasta que pulsemos la tecla F para finalizar el programa.

Si pulsamos la tecla A veremos nuestro menú de Alta de Tareas:

Menú de Alta de Tareas

Si pulsamos INTRO salimos sin realizar ninguna acción.
Pero si escribimos texto y pulsamos INTRO

Mi primera tarea .....

Al escribir texto se creará el fichero TASKer.Entrada en el que se guardarán todas las tareas:

Puedo entrar y salir del programa y probar a incluir nuevas tareas:

Código de la parte 1

Con esto finaliza la primera parte de la programación de TASKer, te recomiendo que edites por tu cuenta cada uno de los ficheros, que pruebes distintas opciones de comandos, que averigues el porque de los bucles while true y como puedes modificarlo o simplificarlo.

Seguramente conozcas el comando select option in ... que te permite gestionar un menú, prueba a modificar el código usando este comando para ver si te resulta más cómodo o no.

Practica y juega con el código sin miedo.

Si por algún motivo algo no te funciona correctamente, te dejo las versiones del código de la parte 1 para que los puedas descargar.
La estructura y ubicación de los ficheros deberá de ser la siguiente:


.
├── lib
│   ├── TLibPantalla
│   ├── TLibTareas
│   └── Tvariables
└── TASKer

2 directories, 4 files

Nos vemos en la segunda parte en la que Organizaremos las Tareas y tendremos que leer y procesar la "Bandeja de entrada de Tareas"

Etiquetas

Luis GuLo

🐧 SysAdmin GNU/Linux - 🐳 Docker - 🖥️ Bash Scripting - 🐪 Perl - 🐬 MySQL - 👥 Formador de TI - 👥 Formador de SysAdmin's - 💢 Ansible - ☁️ Cloud Computing - ❤️ Debian GNU/Linux