2. Estructura básica de shell-scripts. Invocación

En su forma más básica, un shell-script puede ser un simple fichero de texto que contenga uno o varios comandos. Para ayudar a la identificación del contenido a partir del nombre del archivo, es habitual que los shell scripts tengan la extensión «.sh», por lo que seguiremos este criterio (pero recuerde que es algo meramente informativo y opcional). Por ejemplo, el siguiente fichero sería un shell-script:

script.sh
echo "Contenido carpeta personal:"
ls ~/

Tareas

  1. Compruebe que el fichero script.sh tiene permisos de ejecución generales (si no los tuviese, para asignárselos bastaría ejecutar chmod +x script.sh).

  2. Invoque el script para que sea interpretado, usando por ejemplo el comando:

    cd ./script.sh
    

Además de comandos, los shell-scripts pueden contener otros elementos, aportados por el shell para mejorar la funcionalidad de los scripts. De forma resumida, la estructura básica de un shell-script es la siguiente:

script_ejemplo.sh
#!/bin/dash
# Esto es un comentario y no se interpreta
echo Hola
ps w
echo "Proceso lee el script: $$"

En el anterior código, la primera línea es lo que se conoce como «shebang» y la segunda es un comentario. Como contenido del script pueden utilizarse múltiples elementos (comandos, variables, funciones, estructuras de control, comentarios,…) que se analizarán en el siguiente apartado.

El «shebang» permite especificar el intérprete de comandos con el que deseamos que sea interpretado el resto del script cuando se usa invocación implícita (ver más adelante). La sintaxis de esta línea es la secuencia #! seguida del ejecutable del shell deseado, sobre lo que deben realizarse la siguientes advertencias:

  • Es imprescindible que sea la primera línea del script, ya que, en caso contrario, sería interpretado como un comentario (comienza con el carácter #).

  • Puede haber espacios entre #! y el ejecutable del shell.

  • El shebang no es obligatorio (cuando se usa invocación implícita, si no se indica se intentará usar el mismo tipo de shell desde el que se ha invocado el script).

Advertencia

Sintaxis estricta

La sintaxis de los shell-scripts se caracteriza por ser bastante estricta en su escritura, especialmente en lo que se refiere a la inserción u omisión de espacios en blanco entre las palabras especiales. Tenga esto muy en cuenta a la hora de escribir los scripts que se proponen.

La utilización del shebang está condicionada por la forma en que sea invocado el shell-script, existiendo 3 opciones:

  • Explícita: escribiendo explícitamente qué shell se desea invocar y pasando como argumento el nombre del script, cargándose en memoria un nuevo proceso para dicho shell  (subshell o proceso shell hijo del shell padre responsable de la línea de comandos desde la que se ha invocado el script). En este caso se ignora el shebang.

  • Implícita: invocando al script como si fuera un ejecutable, lo que requiere asignar permisos de ejecución al script. Se lee el shebang para determinar qué shell deberá usarse para leer el script, cargándose en memoria un proceso hijo (subshell) para dicho shell (si el script no presenta shebang, para el subshell se utilizará el mismo tipo de shell que el encargado de la línea de comandos desde la que se ha hecho la invocación). Tenga en cuenta que los shell-scripts son ficheros de texto leídos por el intérprete de comandos, esto es, se interpretan, NO se ejecutan. La asignación del permiso de ejecución a un shell-script es una utilidad del sistema de ficheros para acelerar la invocación de scripts, pero cuyo funcionamiento interno es cargar un nuevo proceso de shell (subshell) para que éste interprete el script.

  • Implícita con . (equivale a importar): el script será interpretado por el mismo proceso del shell responsable de la línea de comandos desde la que se está invocando el script (luego aquí no se abre ningún subshell). Consecuentemente, en este caso también se ignora el shebang.

En los casos en los que se crean subshells, salvo que se fuerce lo contrario (con su -c por ejemplo), el subshell pertenecerá al mismo usuario al que pertenecía el shell padre que lo ha creado. El usuario al que pertenece el proceso shell que interpreta un script condiciona las operaciones que se podrán hacer desde dentro del script (por ejemplo, si el shell pertenece al usuario dit, el script no podrá modificar el fichero /etc/passwd, mientras que si el shell pertenece al superusuario root, sí podrá hacerlo). Tenga en cuenta este aspecto para determinar qué operaciones puede realizar dentro de un script, y con qué usuario debe invocarlo.

Tareas

  1. En una consola de comandos ejecute el comando ps w y localice el proceso asociado al shell responsable de la línea de comandos desde la que está trabajando.

  2. Invoque dicho script mediante los distintos métodos de invocación. Para cada uno de ellos, analice la salida obtenida para determinar en cada caso cuál es el proceso shell que está interpretando el script, el usuario al que pertenece dicho proceso y si se ha abierto un subshell o no:

    • Explícita:

      /bin/sh script_ejemplo.sh
      /bin/dash script_ejemplo.sh
      /bin/bash script_ejemplo.sh
      
    • Implícita con .:

      .  script_ejemplo.sh
      
    • Implícita: compruebe que el script tiene permiso de ejecución y ejecútelo con:

      ./script_ejemplo.sh
      

      Modifique el script eliminando el shebang, y vuelva a ejecutarlo. Analice si hay alguna diferencia respecto a la ejecución anterior.

Conforme se ha indicado en la introducción, si bien tanto bash como dash siguen el estándar POSIX, especialmente bash añade múltiples extensiones particulares, no soportadas por otros shells como dash. Consecuentemente, cada vez que diseñemos un script deberemos tener en cuenta el shell o shells que lo soportan, asegurando que sea invocado por uno de ellos. Para que se haga una idea de la importancia de este aspecto, considere los dos scripts siguientes, basados en el uso de la estructura for (que se usará más adelante):

script_estandar.sh
#!/bin/sh
for VAR in 0 1 2 3
do
  echo $VAR
done
script_bash.sh
#!/bin/bash
for ((VAR=0 ; VAR<4 ; VAR++ ))
do
  echo $VAR
done

Ambos scripts realizan la misma funcionalidad, pero script_estandar.sh está escrito bajo la sintaxis POSIX, mientras que script_bash.sh utiliza una sintaxis no estándar soportada por bash.

Tareas

  1. Invoque el guión script_estandar.sh (recuerde que debe disponer de ellos ya creados en el directorio scripts/) mediante los siguientes comandos, debiendo comprobar que todas funcionan correctamente y con igual resultado (la primera y segunda llamada realmente son la misma, usando el shell dash):

    /bin/sh    script_estandar.sh
    /bin/dash  script_estandar.sh
    /bin/bash  script_estandar.sh
    
  2. Ahora invoque el guión script_bash.sh mediante los siguientes comandos:

    /bin/dash  script_bash.sh
    /bin/bash  script_bash.sh
    

    Podrá comprobar cómo, debido a la sintaxis no estándar del script, la segunda invocación funciona, pero la primera (que emplea dash) da un error de sintaxis.