Original article: https://www.freecodecamp.org/news/bash-scripting-tutorial-linux-shell-script-and-command-line-for-beginners/

En Linux, la automatización de procesos se basa fuertemente en la programación de intérprete de comandos (en inglés Shell). Esto involucra el crear un archivo conteniendo una serie de comandos que pueden ser ejecutados juntos.

En este artículo, empezaremos con lo básico de programación de bash el cual incluye variables, comandos, entradas/salidas, y depuración. También veremos ejemplos de cada uno a lo largo.

¡Comencemos! 🚀

Tabla de Contenidos

  1. Pre-requisitos

2. Introducción

3. Cómo empezar con la programación de Bash

4. Lo esencial sobre Programación de Bash

5. Bucles y ramificación en Bash

6. Cómo programar Scripts usando cron

7. Cómo depurar y solucionar problemas de scripts de Bash

8. Conclusión

Pre-requisitos

Para seguir este tutorial, deberías tener los siguientes accesos:

  • Una versión en ejecución de Linux con acceso a la línea de comandos.

Si no tienes Linux instalado o recién estás empezando, puedes fácilmente acceder a la línea de comandos de Linux a través de Replit. Replit es un IDE basado en un navegador donde puedes acceder a la shell de bash en unos pocos minutos.

También puedes instalar Linux sobre tu sistema de Windows usando WSL (Subsistema de Windows para Linux - Windows Subsystem for Linux).

Introducción

Definición de programación de Bash

Un script de Bash es un archivo que contiene una secuencia de comandos que son ejecutados por el programa de bash línea por línea. Te permite realizar una serie de acciones, tales como navegar a un directorio específico, crear una carpeta, y ejecutar un proceso usando la línea de comando.

Al guardar estos comandos en un script, puedes repetir la misma secuencia de pasos múltiples veces y ejecutarlos al correr el script.

Ventajas de la programación de Bash

La programación de Bash es una herramienta poderosa y versátil para automatizar tareas de administración de sistema, gestionar recursos del sistema, y realizar otras tareas rutinarias en sistemas Unix/Linux. Algunas ventajas de la programación de shell son:

  • Automatización: Los scripts de Shell te permiten automatizar tareas y procesos repetitivos, ahorrando tiempo y reduciendo el riesgo de errores que pueden ocurrir con ejecución manual.
  • Portabilidad: Los scripts de Shell pueden ser ejecutados en varias plataformas y sistemas operativos, incluyendo Unix, Linux y macOS, e inclusive Windows a través del uso de emuladores o máquinas virtuales.
  • Flexibilidad: Los scripts de Shell son altamente personalizables y pueden ser fácilmente modificados para adaptarse a requerimientos específicos. También pueden ser combinados con otros lenguajes de programación o utilidades para crear scripts más poderosos.
  • Accesibilidad: Los scripts de Shell son fáciles de escribir y no requieren ninguna herramienta o software especial. Pueden ser editados usando cualquier editor de texto, y la mayoría de los sistemas operativos tienen un intérprete de shell incluido.
  • Integración: Los scripts de Shell pueden ser integrados con otras herramientas y aplicaciones, tales como bases de datos, servidores web, y servicios de la nube, así permitiendo tareas de automatización más compleja y gestión de sistema.
  • Depuración: Los scripts de Shell son fáciles de depurar, y la mayoría de los shells tienen un depurador incorporado y herramientas de reporte de errores que pueden ayudar en identificar y arreglar problemas rápidamente.

Vista general de la terminal de Bash y la interfaz de línea de comandos

Los términos "shell" y "bash" son usados indistintamente. Pero hay una sutil diferencia entre los dos.

El término "shell" se refiere a un programa que provee una interfaz de línea de comandos para interactuar con un sistema operativo. Bash (Bourne-Again SHell) es una de las terminales de Unix/Linux más comúnmente utilizados en muchas distribuciones de Linux.

Una terminal o interfaz de línea de comandos luce de esta forma:

image-135
La terminal acepta comandos del usuario y muestra la salida

En la salida de arriba, zaira@Zaira es el prompt de la shell. Cuando una terminal es usado interactivamente, muestra un $ cuando está esperando un comando del usuario.

Si la terminal se está ejecutando como root (un usuario con permisos administrativos), el prompt se cambia a #. El prompt del shell del superusuario luce así:

[root@host ~]#

Aunque Bash es un tipo de shell, hay otras shells disponibles también, tales como la shell Korn (ksh), la shell C (csh), y la shell Z (zsh). Cada shell tiene su propia sintaxis y conjunto de características, pero todos comparten el propósito en común de proporcionar una interfaz de línea de comandos para interactuar con el sistema operativo.

Puedes determinar tu tipo de shell usando el comando ps:

ps

Esta es la salida para mí:

image-134
Verificando el tipo de shell. Estoy usando la shell de bash

En resumen, mientras que "shell" es un término amplio que se refiere a cualquier programa que proporciona una interfaz de línea de comandos, "Bash" es un tipo específico de shell que es ampliamente usando en sistemas Unix/Linux.

Nota: en este tutorial, estaremos usando la shell "bash".

Cómo empezar con la programación de Bash

Cómo ejecutar comandos de Bash desde la Línea de Comandos

Como mencioné anterioremente, el prompt de la shell luce así:

[username@host ~]$

Puedes ingresar cualquier comando después del signo $ y ver la salida de la shell.

Generalmente, los comandos siguen esta sintaxis:

comando [OPCIONES] argumentos

Discutamos unos pares de comandos de bash básicos y veamos sus salidas. Asegúrate de seguirme :)

  • date: Muesta la fecha actual.
zaira@Zaira:~/shell-tutorial$ date
Tue Mar 14 13:08:57 PKT 2023
  • pwd: Muestra la carpeta de trabajo presente.
zaira@Zaira:~/shell-tutorial$ pwd
/home/zaira/shell-tutorial
  • ls: Lista los contenidos de la carpeta actual.
zaira@Zaira:~/shell-tutorial$ ls
check_plaindrome.sh  count_odd.sh  env  log  temp
  • echo: Imprime una cadena de texto, o el valor de una variable a la terminal.
zaira@Zaira:~/shell-tutorial$ echo "Hello bash"
Hello bash

Siempre puedes referirte al manual de los comandos con el comando man.

Por ejemplo, el manual para ls se ve así:

image-138
Puedes ver las opciones para un comando en detalle usando man

Cómo crear y ejecutar scripts de Bash

Convenciones de nombramiento de Script

Por convención de nomenclatura, los scripts de bash terminan con .sh. Sin embargo, los scripts de bash pueden ejecutarse perfectamente sin la extensión sh.

Agregando el Shebang

Los scripts de Bash comienzan con un shebang. Shebang es una combinación de bash # y bang ! seguido del path de la shell de bash. Esta es la primer línea del script. Shebang le dice a la shell que lo ejecute por medio de la shell de bash. Shebang es simplemente un path absoluto al intérprete de bash.

Abajo hay un ejemplo de la sentencia shebang.

#!/bin/bash

Puedes encontrar tu path de la shell de bash (el cual podría variar del de arriba) usando el comando:

which bash

Creando nuestro primer script de bash

Nuestro primer script le dice al usuario que ingrese una ruta. Como respuesta, su contenido será listado.

Crea un archivo llamado run_all.sh usando el comando vi. Puedes usar cualquier editor de tu preferencia.

vi run_all.sh

Agrega los siguientes comandos en tu archivo y guárdalo:

#!/bin/bash
echo "Hoy es " `date`

echo -e "\ningresa la ruta al directorio"
read the_path

echo -e "\n tu ruta tiene los siguientes archivos y carpetas: "
ls $the_path
Script para imprimir los contenidos de una carpeta proporcionada por un usuario

Miremos aún más de cerca al script línea por línea. Estoy mostrando el mismo script de nuevo, pero esta vez con números de línea.

  1 #!/bin/bash
  2 echo "Hoy es " `date`
  3
  4 echo -e "\nIngresa la ruta al directorio"
  5 read the_path
  6
  7 echo -e "\n tu ruta tiene los siguientes archivos y carpetas: "
  8 ls $the_path
  • Línea #1: El shebang (#!/bin/bash) apunta hacia la ruta de la shell de bash.
  • Línea #2: El comando echo muestra la fecha actual y el tiempo en la shell. Nota que el date está con comillas invertidas.
  • Línea #4: Queremos que el usuario ingrese una ruta válida.
  • Línea #5: El comando read lee la entrada y lo almacena en la variable the_path.
  • Línea #8: El comando ls toma la variable con la ruta almacenada y muestra los archivos y las carpetas actuales.

Ejecutando el script del bash

Para hacer que el script sea ejecutable, asigna permisos de ejecución para tu usuario usando este comando:

chmod u+x run_all.sh

Aquí,

  • chmod modifica la posesión de un archivo para el usuario actual :u.
  • +x agrega los privilegios de ejecución al usuario actual. Esto significa que el usuario quien es el propietario ahora puede ejecutar el script.
  • run_all.sh es el archivo que deseamos ejecutar.

Ahora puedes ejecutar el script usando cualquiera de los métodos mencionados:

  • sh run_all.sh
  • bash run_all.sh
  • ./run_all.sh

Veámoslo ejecutando una acción 🚀

run-script-bash-2

Lo esencial sobre Programación de Bash

Comentarios en programación de bash

Los comentarios comienzan con un # en programacioń de bash. Esto significa que cualquier línea que comience con un # es un comentario y será ignorado por el intérprete.

Los comentarios son muy útiles al documentar el código, y es una buena práctica agregarlos para ayudar a los demás entender el código.

Estos son ejemplos de comentarios:

# Este es un comentario de ejemplo
# Estas dos líneas serán ignoradas por el intérprete

Variables y tipos de datos en Bash

Las variables te permiten almacenar datos. Puedes usar variables para leer, acceder, y manipular datos en todo tu script.

No hay tipos de datos en Bash. En Bash, una variable es capaz de almacenar valores numéricos, caracteres individuales, o cadenas de caracteres.

En Bash, puedes usar y establecer los valores de variable de las siguientes formas:

  1. Asignar el valor directamente:
pais=Pakistan

2.  Asignar el valor basado en la salida obtenida de un programa o de un comando, usando la substitución de comando. Ten en cuenta que $ se requiere para acceder a un valor de una variable existente.

mismo_pais=$pais
Esto asigna el valor de pais a la nueva variable mismo_pais

Para acceder al valor de la variable, adjunta $ al nombre de la variable.

zaira@Zaira:~$ pais=Pakistan
zaira@Zaira:~$ echo $pais
Pakistan
zaira@Zaira:~$ nuevo_pais=$pais
zaira@Zaira:~$ echo $nuevo_pais
Pakistan
Asignar e imprimir valores de variables

Convenciones de nomenclatura de Variable

En programación de Bash, las convenciones de nomenclatura de variable son los siguientes:

  1. Los nombres de variable deberían comenzar con una letra o un guión bajo (_).
  2. Los nombres de variable pueden contener letras, números, y guiones bajos (_).
  3. Los nombres de variable se distinguen entre mayúsculas y minúsculas.
  4. Los nombres de variable no deberían contener espacios o caracteres especiales.
  5. Usa nombres descriptivos que reflejen el propósito de la variable.
  6. Evitar usar palabras claves reservadas, tales como if, then, else, fi, y así sucesivamente como nombres de variable.

Aquí hay algunos ejemplos de nombres de variable válidos en Bash:

nombre
cuenta
_var
miVar
MI_VAR

Y aquí hay algunos ejemplos de nombres de variable inválidos:

2ndvar (el nombre de variable comienza con un número)
mi var (el nombre de variable contiene un espacio)
mi-var (el nombre de variable contiene un guión)

Siguiendo estas convenciones de nomenclatura ayuda en hacer los scripts de Bash más legibles y más facil de mantener.

Entradas y salidas en scripts de Bash

Recopilación de entradas

En esta sección, discutiremos algunos de los métodos para proveer entrada a nuestros scripts.

  1. Leer la entrada del usuario y almacenarlo en una variable

Podemos leer la entrada de usuario usando el comando read.

#!/bin/bash
echo "Hoy es " `date`

echo -e "\ningresa la ruta al directorio"
read la_ruta

echo -e "\ntu ruta tiene los siguientes archivos y carpetas: "
ls $la_ruta
name-sh

2.  Leer de un archivo

Este código lee cada línea de un archivo llamado input.txt y lo imprime en la shell. Estudiaremos bucles de while más adelante en este artículo.

while read linea
do
  echo $linea
done < input.txt

3.  Argumentos de Línea de Comando

En un script bash o una función, $1 denota el argumento inicial pasado $2 denota el segundo argumento pasado, y así sucesivamente.

Este script toma un nombre como un argumento de línea de comando e imprime un saludo personalizado.

echo "Hello, $1!"

Hemos suplido Zaira como nuestro argumento al script.

#!/bin/bash
echo "Hello, $1!"
El código para el escript: greeting.sh

Salida:

name-sh-1

Mostrando la salida

Aquí discutiremos algunos de los métodos para recibir salida de los scripts.

  1. Imprimir en la terminal:
echo "Hola, Mundo!"

Esto imprime el texto "Hola, Mundo!" en la terminal.

2.  Escribir a un archivo:

echo "Esto es un texto." > output.txt

Esto escribe el texto "Esto es un texto." a un archivo llamado output.txt. Ten en cuenta que el operador > sobrescribe un archivo si éste ya tiene algún contenido.

3.  Adjuntar a un archivo:

echo "Mas texto." >> output.txt

Esto adjunta el texto "Mas texto." al final del archivo output.txt.

4.  Redireccionando la salida:

ls > files.txt

Esto lista los archivos en el directorio actual y escribe la salida a un archivo llamado files.txt. Puedes redirigir la salida de cualquier comando a un archivo de este forma.

Comandos básicos de Bash (echo, read, etc.)

Aquí hay una lista de algunos de los comandos de bash más comúnmente usados:

  1. cd: Cambia el directorio a un lugar distinto.
  2. ls: Lista los contenidos del directorio actual.
  3. mkdir: Crea un nuevo directorio.
  4. touch: Crea un nuevo archivo.
  5. rm: Elimina un archivo o un directorio.
  6. cp: Copia un archivo o un directorio.
  7. mv: Mueve o renombra un archivo o un directorio.
  8. echo: Imprime texto a la terminal.
  9. cat: Concatena e imprime los contenidos de un archivo.
  10. grep: Busca un patrón en un archivo.
  11. chmod: Cambia los permisos de un archivo o de un directorio.
  12. sudo: Ejecutar un comando con privilegios administrativos.
  13. df: Mostrar la cantidad de espacio de disco disponible.
  14. history: Mostrar una lista de comandos ejecutados previamente.
  15. ps: Mostrar información sobre procesos en ejecución.

Declaraciones condicionales (if/else)

Expresiones que producen un resultado booleano, sea verdadero o falso, son llamados condiciones. Hay varias formas de evaluar condiciones, incluyendo if, if-else, if-elif-else, y condicionales anidadas.

Sintaxis:

if [[ condicion ]];
then
	declaracion
elif [[ condicion ]]; then
	declaracion 
else
	haz esto por defecto
fi
Sintaxis de declaraciones condicionales de bash

Podemos usar operadores lógicos tales como AND -a y OR -o para hacer comparaciones que tienen más significado.

if [ $a -gt 60 -a $b -lt 100 ]
Esta sentencia vertifica si ambas condiciones son true: a es mayor que 60 AND b es menor que 100.

Veamos un ejemplo de un script de Bash que usa declaraciones de if, if-else, y if-elif-else para determinar si el número introducido por el usuario es positivo, negativo, o cero:

#!/bin/bash

echo "Por favor ingresa un numero: "
read num

if [ $num -gt 0 ]; then
  echo "$num es positivo"
elif [ $num -lt 0 ]; then
  echo "$num es negativo"
else
  echo "$num es cero"
fi
Script para determinar si un número es positivo, negativo, o cero

El script primero imprime un mensaje al usuario para que ingrese un número. Luego, usa una declaración if para verificar si el número es mayor que 0. Si lo es, el script muestra que el número es positivo. Si el número no es mayor que 0, el script se mueve a la siguiente declaración, el cual es una declaración if-elif. Aquí, el script verifica si el número es menor que 0. Si lo es, el script muestra que el número es negativo. Finalmente, si el número ni es mayor que 0 ni menor que 0, el script usa una declaración else para mostrar que el número es cero.

Míralo en acción 🚀

test-odd

Bucles y ramificación en Bash

Bucle While

Los bucles while verifican una condición y hacen un bucle hasta que la condición sea true. Necesitamos proveer un contador que vaya incrementándose para controlar la ejecución del bucle.

En el ejemplo de abajo, (( i += 1 )) está la declaración contador que incrementa el valor de i. El bucle lo ejecutará exactamente 10 veces.

#!/bin/bash
i=1
while [[ $i -le 10 ]] ; do
   echo "$i"
  (( i += 1 ))
done
Bucle while que itera 10 veces.
image-187

Bucle for

El bucle for, así como el bucle while, te permite ejecutar declaraciones en un número específico de veces. Cada bucle difiere en su sintaxis y uso.

En el ejemplo de abajo, el bucle iterará 5 veces.

#!/bin/bash

for i in {1..5}
do
    echo $i
done
Bucle for que itera 5 veces.
image-186

Declaraciones Case

En Bash, las declaraciones case son usados para comparar un valor dado con una lista de patrones y ejecutar un bloque de código basado en el primer patrón que coincida. La sintaxis para una declaración case en Bash es como lo que sigue:

case expression in
    pattern1)
        # código a ejecutar si la expresión coincide con pattern1
        ;;
    pattern2)
        # código a ejecutar si la expresión coincide con pattern2
        ;;
    pattern3)
        # código a ejecutar si la expresión coincide con pattern3
        ;;
    *)
        # código a ejecutar si ninguno de los patrones de arriba coincide con la expresión
        ;;
esac
Sintaxis de las declaraciones Case

Aquí, "expression" es el valor que queremos comparar, y "pattern1", "pattern2", "pattern3", y así sucesivamente son los patrones con los que queremos comparar.

El doble punto y coma ";;" separa cada bloque de código para ejecutar cada patrón. El asterisco "*" representa el caso por defecto, el cual se ejecuta si ninguno de los patrones especificados coinciden con la expresión.

Veamos un ejemplo:

fruta="manzana"

case $fruta in
    "manzana")
        echo "Este es una fruta roja."
        ;;
    "banana")
        echo "Este es una fruta amarilla."
        ;;
    "orange")
        echo "Este es una fruta naranja."
        ;;
    *)
        echo "Fruta desconocida."
        ;;
esac
Ejemplo de la declaración case

En este ejemplo, ya que el valor de "fruta" es "manzana", el primer patrón coincide, y el bloque de código que imprime "Este es una fruta roja." Se ejecuta. Si el valor de "fruta" fuere "banana", el segundo patrón coincidiría y el bloque de código que imprime "Este es una fruta amarilla." Se ejecutaría, y así sucesivamente. Si el valor de "fruta" no coincide con ninguno de los patrones especificados, el caso por defecto se ejecuta, el cual imprime "Fruta desconocida."

Cómo programar Scripts usando cron

Cron es una utilidad poderosa para programar trabajos que está disponible en sistemas operativos tipo Unix. Al configurar cron, puedes configurar trabajos automatizados que se ejecuten diariamente, semanalmente, mensualmente, o en una base de tiempo específica. Las capacidades de automatización provista por cron juegan un papel crucial en la administración del sistema Linux.

Abajo está la sintaxis para programar crons:

# Ejemplo de un trabajo Cron 
* * * * * sh /path/to/script.sh

Aquí, los * representan minuto(s) hora(s) día(s) mes(es) semana(s), respectivamente.

Abajo hay algunos ejemplos de programación de trabajos cron.

Programar Descripción Ejemplo
0 0 * * * Ejecuta un script a medianoche cada día 0 0 * * * /ruta/a/script.sh
*/5 * * * * Ejecuta un script cada 5 minutos */5 * * * * /ruta/a/script.sh
0 6 * * 1-5 Ejecuta un script a las 6 am de Lunes a Viernes 0 6 * * 1-5 /ruta/a/script.sh
0 0 1-7 * * Ejecuta un script en los primeros 7 días de cada mes 0 0 1-7 * * /ruta/a/script.sh
0 12 1 * * Ejecuta un script en el primer día de cada mes al mediodía 0 12 1 * * /ruta/a/script.sh

Usando crontab

La utilidad crontab es usado para agregar y editar los trabajos cron.

crontab -l lista los scripts ya programados para un usuario particular.

Puedes agregar y editar el cron con crontab -e.

Puedes leer más sobre los trabajos cron en mi otro artículo aquí.

Cómo depurar y solucionar problemas de scripts de Bash

Depurar y solucionar problemas son habilidades esenciales para cualquier programador de Bash. Mientras que los scripts de Bash pueden ser increíblemente poderosos, también pueden ser propicios a tener errores y con comportamientos inesperados. En esta sección, discutiremos algunos consejos y técnicas para depurar y solucionar problemas en scripts de Bash.

Establecer la opción set -x

Una de las técnicas más útiles para depurar scripts de Bash es establecer la opción set -x al principio del script. Esta opción permite el modo en depuración, el cual hace que Bash imprima cada comando que ejecuta a la terminal, precedido por un signo +, Esto puede ser increíblemente útil al identificar dónde ocurren los errores en tu script.

#!/bin/bash

set -x

# Tu script va aquí

Verifica el código de salida

Cuando Bash encuentra un error, pone un código de salida que indica la naturaleza del error. Puedes verificar el código de salida del comando más reciente usando la variable $?. Un valor de 0 indica éxito, mientras que cualquier otro valor indica un error.

#!/bin/bash

# Tu script va aquí

if [ $? -ne 0 ]; then
    echo "Hubo un error."
fi

Usa declaraciones echo

Otra técnica útil para depurar scripts de Bash es insertar declaraciones echo a lo largo de tú código. Esto puede ayudarte en identificar cuando ocurren los errores y qué valores están siendo pasados a las variables.

#!/bin/bash

# Tu script va aquí

echo "El valor de la variable x es: $x"

# Más código va aquí

Usa la opción set -e

Si quieres que tu script salga inmediatamente cuando cualquier comando en el script falle, puedes usar la opción set -e. Esta opción hará que Bash salga con un error si cualquier comando en el script falle, haciendo más fácil de identificar y arreglar errores en tu script.

#!/bin/bash

set -e

# Tu script va aquí

Resolviendo problemas de crons verificando los logs

Podemos solucionar problemas de crons usando los archivos de log. Los logs son mantenidos para todos los trabajos programados. Puedes verificar en los logs si un trabajo específico se ejecutó como se pretendía o no.

Para Ubuntu/Debian, puedes encontrar los logs de cron en:

/var/log/syslog

La ubicación varía para otras distribuciones.

Un archivo log de un trabajo de cron luce así:

2022-03-11 00:00:01 Tarea iniciada
2022-03-11 00:00:02 Ejecutando script /ruta/a/script.sh
2022-03-11 00:00:03 El script se completó exitosamente
2022-03-11 00:05:01 Tarea iniciada
2022-03-11 00:05:02 Ejecutando script /ruta/a/script.sh
2022-03-11 00:05:03 Error: no se pudo conectar a la base de datos
2022-03-11 00:05:03 El script salió con código de error 1
2022-03-11 00:10:01 Tarea iniciada
2022-03-11 00:10:02 Ejecutando script /ruta/a/script.sh
2022-03-11 00:10:03 El script se completó exitosamente 
Log de un Cron (un ejemplo en español)

Conclusión

En este artículo, comenzamos con cómo acceder a la shell y luego ejecutamos algunos comandos básicos de Bash. También estudiamos lo que es una terminal de Bash. Brevemente, miramos la ramificación de código usando bucles y condicionales. Finalmente, discutimos sobre automatizar los scripts usando cron seguido de algunas técnicas de solución de problemas.

Recursos para aprender más sobre programación de Bash

Si quieres indagar más profundamente en el mundo de la programación de Bash, te sugeriría que mires a este curso de 6 horas en Linux en freeCodeCamp (en inglés).

¿Qué es lo que más te gusta de lo que aprendiste de este tutorial? Puedes también contactarme en cualquiera de estas plataformas. 📧�

Nos vemos en el próximo tutorial, feliz codificación 😁

Créditos de la imagen de portadas: Imagen por Freepik