Scripting en Linux (V): Bash. Ejecutar un Script en el Inicio o Apagado

Muy buenas. Ahí va otro post de la serie de Linux Scripting. Ahora que ya conoces más el entorno de Bash, la sintaxis básica del lenguaje, y los pasos a seguir para ejecutar tu primer script de forma manual, en este post verás como automatizar la ejecución.

Concretamente, me centrare en los tres principales métodos de los que disponemos a día de hoy: utilizar Cron y Crontab, crear un servicio en systemd que contenga el script, o editar el fichero /etc/rc.d/rc.local, que era el método clásico antes de la llegada de systemd ¡Vayamos al detalle!

Tabla de contenidos:

  1. Primeros pasos: preparar el script
  2. Método 1: utilizar Cron y Crontab
  3. Método 2: crear un servicio en systemd
  4. Método 3: utilizar /etc/rc.d/rc.local
  5. Continuación

Primer Paso. Preparar Script

Como punto de partida, y antes de empezar con lo importante, voy a suponer que parto del script que creamos en el post anterior de esta serie, que básicamente se encarga de comprobar si hay actualizaciones en el equipo, e indicar en un fichero de log la fecha y hora de ejecución del script (esto me lo he puesto solo para comprobar, una vez arrancado el sistema, que se ha ejecutado correctamente).

#!/bin/bash

sudo apt update
echo "script ejecutado - $(date)" >> /home/test/Documentos/log-script.txt

exit

El script, para esta prueba, lo he guardado en Documentos, dentro de mi directorio personal. Recuerda también que, como explico en el post anterior, tenemos que proporcionar permisos de ejecución a este fichero.

Hecho todo esto, paso ya a detallar los diferentes métodos que puedes utilizar para ejecutar este script de forma automática, en cada inicio o apagado del equipo.

Método 1: Utilizar Cron y Crontab

Cron es una herramienta que se utiliza en GNU/Linux y Unix, y que sirve para programar la ejecución de comandos o scripts en el sistema, en base a una fecha y hora específicas. Cron permanece siempre activo y en segundo planto. Esto lo puedes comprobar fácilmente a través del servicio o demonio asociado a Cron, que se denomina crond.

Por otra parte, tenemos al fichero Crontab, que es básicamente donde indica toda la relación de scripts y/o comandos que deben ejecutarse de forma automática, en base a la fecha y hora asignadas. Para ver y editar ese fichero, se utiliza el comando crontab, que facilita esa gestión sin tener que utilizar la ruta del fichero.

Lo primero sería visualizar el contenido de ese fichero en tu sistema. Para ello puedes utilizar el comando que te dejo a continuación. Como podemos tener un fichero Crontab a nivel de usuario, puedes visualizar el que está asociado a tu cuenta de usuario (sin poner «sudo» delante), o el que está asociado a root, que sería el que aplica al conjunto del sistema (anteponiendo «sudo» delante):

sudo crontab -l

En una instalación limpia, lo más probable es que la salida del comando te indique que el fichero está vacío. En mi caso, por ejemplo, me ha salido el output que te muestro a continuación, que básicamente indica que no hay ninguna tabla específica asociada al usuario root.

no crontab for root - using an empty one

El siguiente paso, por tanto, es rellenar el fichero con la tarea que quieres que se ejecute de forma automática, e indicar el contexto de ejecución. Para ello, debes hacer uso del siguiente comando:

sudo crontab -e

A continuación se te preguntará, en primer lugar, que tipo de editor quieres utilizar para editar el fichero. Yo he indicado la opción 1, que es la que corresponde a Nano, ya que es el editor por consola que conozco mejor y que me parece más simple e intuitivo de utilizar. Lo siguiente que verás es la interfaz del editor Nano por pantalla, y ya solo queda empezar a editar el fichero.

Para ello, debes especificar cada tarea a ejecutar en una linea aparte, y siguiendo el siguiente formato:

* * * * * orden-ejecución

Los asteriscos van separados por un espacio y sirven para indicar el contexto de ejecución. Puedes sustituir cada uno de ellos con el valor correspondiente en cada uno de estos casos:

  • Minuto. Indicar un valor de 0 a 59.
  • Hora. Indicar un valor de 0 a 23.
  • Día del més. Indicar un valor de 1 a 31.
  • Mes. Indicar un valor de 1 a 12.
  • Día de la semana. Indicar un valor de 0 (domingo) a 6 (sábado).

Otra opción para indicar el contexto de ejecución es sustituir todos los asteriscos por una sola palabra reservada, que no necesariamente tenga que estar relacionada con un hito de calendario. Existen varias de ellas, pero la que nos interesa en nuestro caso es la siguiente:

  • @reboot. Ejecución una sola vez durante el arranque

La ultima parte es la orden de ejecución, que basicamente es el comando que debe ejecutarse, o bien, como ocurre en este caso, la ruta del script que queremos ejecutar. Con todo esto, la línea que tienes que añadir en tu fichero crontab quedaría así:

@reboot /home/test/Documentos/scripts/mi-primer-script.sh

Con esto ya tienes el fichero crontab configurado para ejecutar el script en cada arranque del sistema. Antes de dar por bueno el proceso, queda la tarea de comprobar que el servicio asociado a Cron esté habilitado, de lo contrario, no se ejecutaría ninguna de las tareas que especificases en crontab.

Esto, en un contexto de systemd, puedes hacerlo con el comando que te indico a continuación. Recuerda que, en Debian, Ubuntu y otras distros derivadas, el servicio se denomina cron, pero en otros sistemas como Fedora o CentOS, el nombre correcto del servicio es crond.

sudo systemctl status cron.service

Lo más habitual es que te indique que el servicio está activo. Si por lo que fuera, te indicase lo contrario, puedes habilitarlo con el siguiente comando:

sudo systemctl enable cron.service

Con esto si que ya tienes el script preparado para que se ejecute en cada arranque del sistema.

Método 2: Crear un Servicio en systemd

El segundo método que explicaré funciona dentro del contexto de systemd, por lo que solamente será válido en el caso de que tu distribución haga uso de systemd como sistema de inicio predeterminado.

Esto es muy probable que sea así, puesto que, a pesar de toda la controversia que ha traído, es el sistema de inicio que han ido adoptando muchas de las distribuciones GNU/Linux más populares, empezando por Fedora en 2011, y siguiendo con openSUSE, Ubuntu o Debian (junto con todo el conjunto de derivadas de estas dos ultimas).

Aunque systemd nació originalmente como un sustituto de SysV, el sistema de inicio heredado de los sistemas operativos Unix, systemd absorbe la gestión de muchos otros componentes del sistema, con las ventajas y los problemas que ello conlleva. El tema da mucho de que hablar, pero nos desviaríamos del alcance de este post.

Como systemd se encarga también de la gestión de servicios, puedes ejecutar un script en el inicio creando un servicio a través de systemd que haga una llamada a tu script. Así pues, el primer paso es crear el servicio. Para ello, puedes crear un fichero con cualquier editor de texto, y escribir lo siguiente:

[Unit]
Description=Script service
After=network.target network-online.target
Wants=network-online.target

[Service]
ExecStart=/home/test/Documentos/mi-primer-script.sh

[Install]
WantedBy=multi-user.target

Como ves, el contenido consta de tres bloques (puede haber más, pero para este ejemplo me he centrado en estos tres), con una serie de atributos o directivas en cada uno de ellos.

En el primer bloque es Unit, y en este ejemplo sencillo le he indicado las siguientes directivas (puede tener muchas más según los requerimientos del servicio).

  • Description. Puedes indicar una descripción simple del servicio. Aquí no hay mucho misterio.
  • After. Sirve para controlar el orden de ejecución. En este caso, por ejemplo, nos interesa que el servicio se ejecute después de haber iniciado toda la capa de red. Lo tienes explicado mucho más en detalle aquí.
  • Wants. Esto viene a ser una versión ligera de Requires. Significa que systemd intentará arrancar todas las unidades listadas aquí, en el momento de arrancar la unidad actual.

El segundo bloque es Service. bloque es donde se indica la ruta absoluta del fichero a ejecutar (que en nuestro caso es el script que hemos creado en la primera parte del post).

  • ExecStart. Aquí es donde debes indicar la tura completa, junto con los argumentos que convengan, del comando o el script que quieres ejecutar. En este caso, simplemente indicamos la ruta de nuestro primer script de prueba.

El tercer bloque que he utilizado es Install.

El fichero debes guardarlo con un nombre terminado con la extensión .service. y almacenarlo en el directorio /etc/systemd/system. En mi caso lo he guardado como mi-primer-servicio.service.

El ultimo paso es habilitar el servicio para que inicie con cada inicio del sistema. Esto puedes hacerlo con el siguiente comando (como ves, no hace falta indicar la extensión .service al final):

sudo systemctl enable mi-primer-servicio

También puedes iniciar un servicio de forma manual en cualquier momento. Para ello utiliza:

sudo systemctl start mi-primer-servicio

Además, en cualquier momento puedes comprobar que el servicio está cargado en el equipo. Para ello escribe esto:

sudo systemctl status mi-primer-servicio

Como comprobación final, quedaría comprobar que, después del primer reinicio, el script se ha ejecutado correctamente. Para ello puedes aprovecharte de el hecho que, en el propio script, hemos escrito una línea en un fichero de log almacenado en documentos.

Método 3: Utilizar /etc/rc.d/rc.local

El último método es probablemente el más clásico, y que solía funcionar muy bien antes de la llegada de systemd en gran parte de las distribuciones. Consiste básicamente en añadir las órdenes que deseas ejecutar en el inicio del sistema, al final del fichero /etc/rc.d/rc.local.

Lo que ocurre es que, con la llegada de systemd, el fichero en cuestión de gobierna a través de un servicio de systemd, que en muchos casos está inactivo. De hecho, esto puedes comprobarlo a través del siguiente comando:

sudo systemctl status rc-local

Al hacer esto en Ubuntu 18.04 LTS, lo más probable es que obtengas una salida como la que me ha aparecido a mi:

● rc-local.service - /etc/rc.local Compatibility
Loaded: loaded (/lib/systemd/system/rc-local.service; static; vendor preset:
Drop-In: /lib/systemd/system/rc-local.service.d
└─debian.conf
Active: inactive (dead)
Docs: man:systemd-rc-local-generator(8)

Esto indica que este servicio ya no se utiliza, por lo que el método que propongo a continuación no podrás utilizarlo en tu sistema.

Continuación

Con esta guía ya tienes el proceso general a seguir en el momento de crear y ejecutar un script con Bash. En próximos post verás como ejecutar un script de forma automática en el inicio o apagado del sistema. Antes de finalizar, te dejo a continuación con el resto de posts de esta serie.

  1. Linux scripting. Descubre el enorme poder de automatizar tareas
  2. Linux scripting con Bash. Introducción a Bash
  3. Linux scripting con Bash. Sintaxis del lenguaje
  4. Linux scripting con Bash. Crear y ejecutar tu primer script
  5. Linux scripting con Bash. Ejecutar script en el inicio del sistema
  6. Linux scripting con Bash. Ejemplo: setup post-instalación para Ubuntu
  7. Linux scripting con Bash. Ejemplo: programar analisis semanal contra virus y rootkits

Un saludo y hasta la próxima!

Referencias

A continuación tienes un listado de las referencias que he utilizado para documentarme. Si quieres profundizar más en todo lo que explico en el post, te vendrá bien su lectura:

Categorías LinuxEtiquetas

5 comentarios en “Scripting en Linux (V): Bash. Ejecutar un Script en el Inicio o Apagado

  1. Humberto Muñoz 15 Jul 2022 — 16:30

    Muchas Gracias por la info y por como haces que la explicación sea entendible, Me encanta tu blog!! le daré todo el recorrido, porque me interesa aprender Linux, solo estaría bien que fueras mas especifico, me trabe mucho con el tema de la edición del archivo crontab, ya que no sabia como guardarlo, editarlo , etc. Aun así , me diste las bases para resolver mi problema

    Me gusta

  2. genial el post y el blog!!
    por cierto, en la opción de systemctl, el wantedby lleva un punto antes de target:
    WantedBy=multi-user.target

    :)

    Me gusta

    1. Muchas gracias por la corrección Lupo!
      Lo acabo de modificar ahora mismo!
      Un abrazo!

      Me gusta

  3. El directorio del texto «El fichero debes guardarlo con un nombre terminado con la extensión .service. y almacenarlo en el directorio /etc.systemd/system. En mi caso lo he guardado como mi-primer-servicio.service», no se encuentra en el sistema (linux mint). Creo que debería ser «/etc/systemd/system»

    Me gusta

    1. Hola Matrovska, tienes toda la razón. Error mio, la ruta correcta es la que indicas tu. Lo acabo de corregir ahora.
      Muchas gracias por mencionarlo!

      Me gusta

Deja un comentario

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.

search previous next tag category expand menu location phone mail time cart zoom edit close