Incluir otros ficheros en BASH

En ocasiones nuestros scripts en bash se hacen demasiado largos y complejos. También es posible que haya partes comunes a varios scripts. En estas ocasiones puede ser conveniente separar parte del código en varios ficheros. O incluso podríamos querer cargar los datos de configuración qu estén en otro fichero.

Pero ¿cómo hacemos para usar código que hay en otro script en el nuestro?

Incluir un fichero en un script

Incluir código en un script es muy sencillo, basta con usar una de estas opciones:

. fichero
source fichero

Veamos un ejemplo. Crea un fichero llamado prueba y copia el siguiente código:

#!/bin/bash
echo "Voy a incluir el otro fichero"
. otro_fichero
echo "El otro fichero ha sido incluido"

y necesitamos otro fichero al que, de manera muy imaginativa, vamos a llamar otro_fichero. Copia en él el siguiente código:

echo "Este es el otro fichero"

No olvides hacer que prueba sea ejecutable:

$ chmod +x prueba

El resultado al ejecutarlo será:

$ ./prueba
Voy a incluir el otro fichero
Este es el otro fichero
El otro fichero ha sido incluido

¿Debo usar source o ‘.’?

Source no es POSIX (por resumir muuucho digamos que POSIX es un estándar para, entre otras cosas los intérpretes de comandos o shell) así que puede no estar disponible en tu consola.

En Bash sí está disponible y es exactamente lo mismo source que ‘.’ así que puedes usarlos indistintamente.

Diferencias entre ejecutar un script e incluirlo

Posiblemente te habrás fijado en que otro_fichero no es ejecutable pero se ha ejecutado el código que había en su interior.

Si hubiésemos hecho dentro de script:

#!/bin/bash

./otro_fichero

El resultado hubiese sido un error porque otro_fichero no es ejecutable:

$ ./prueba
./script: línea 3: ./otro: Permiso denegado

Es decir, al incluir un fichero lo que hacemos es “copiar” el contenido de ese fichero en nuestro script. Es como si ese código estuviese dentro del fichero que estamos ejecutando.

Si usamos la opción de ejecutar otro_fichero estamos llamando a un script externo y ése deberá tener sus permisos de ejecución.

Problemas de seguridad

Incluir un fichero puede ser una fuente de problemas de seguridad. Imagina un script que se ejecuta como root. Este script incluye un fichero que está en la carpeta a la que tienen acceso otros usuarios. Un usuario malvado y malandrín podría hacer cambios en ese fichero incluido y ejecutar los comandos que quiera. ¡Y esos comandos se ejecutarán como administrador!

Veamos un ejemplo. Por un lado tenemos el fichero script:

#!/bin/bash
. otro_fichero
y por otro lado tenemos otro_fichero en el que teclearemos:
whoami

NOTA: whoami es un comando que nos muestra el usuario con el que estamos ejecutando comandos.

El resultado será:

$ ./prueba
gorka

En mi caso se muestra mi nombre de usuario.

Ahora cambia de cuenta y accede como root (puedes hacerlo directamente tecleando):

$ sudo -i

y en una carpeta a la que solo tenga acceso este usuario root crea el fichero prueba con el siguiente contenido:

#!/bin/bash
. /home/gorka/otro_fichero

Creo que sobra decir que en lugar de /home/gorka tendrás que poner la ruta donde tengas otro_fichero.

Hazlo ejecutable:

$ chmod +x prueba

Ahora ejecuta el fichero y verás el escalofriante resultado:

$ ./prueba
root

¡El comando whois se ha ejecutado usando el usuario root! Imagina si hubiesen metido cualquier cosa desagradable ahí.

En una próxima entrega veremos cómo filtrar un fichero de configuración para poder incluirlo sin tanto peligro.

Mi script no encuentra el fichero que quiero incluir

En los primeros ejemplos hemos visto que para incluir un fichero simplemente escribíamos su nombre. Pero eso puede ser una fuente de problemas. Por ejemplo, si llamas desde un cron o desde otra carpeta puede que tu script no encuentre el fichero que quieres incluir. Vamos a verlo.

Tenemos el fichero prueba:

#!/bin/bash

./otro_fichero

y el fichero otro_fichero:

echo "Soy el otro fichero"

Al ejecutar prueba:

$ ./prueba
Soy el otro fichero

Ahora prueba a cambiar de carpeta. En mi caso yo he guardado el fichero en una carpeta llamada /home/gorka/pruebas. Voy a ejecutar el script desde la carpeta /home/gorka:

$ pruebas/prueba
pruebas/script: línea 3: otro_fichero: No existe el archivo o el directorio

¿Por qué sucede ésto? Porque prueba está buscando el fichero otro_fichero en la carpeta donde se está ejecutando (en este caso en /home/gorka).

Esto mismo te va a suceder cuando ejecutes el script desde un cron o desde otro usuario. Hay que tener cuidado.

¿Cómo podemos evitarlo? Hay varias posibles soluciones, pero una de las más seguras es usar la variable de entorno $BASH_SOURCE:

#!/bin/bash
ruta_completa=${BASH_SOURCE[0]}
carpeta_script=${ruta_completa%/*}
. $carpeta_script/otro_fichero

Ahora sí funcionará:

$ pruebas/prueba
Soy el otro fichero

NOTA: Este “truco” no funciona con enlaces simbólicos. En otra entrega hablaré sobre para qué sirve $BASH_SOURCE y cómo hacer funcionar ésto con enlaces simbólicos.

Autor:
Nivel: Principiante
Palabras clave:
Fecha publicado:
Fecha actualizado: 13-01-2017

Otros capítulos de la misma serie

Este capítulo es parte de la serie: Programación en BASH.

Y muchos más en preparación.

Disponible en los planes: Laravel hero PHP a tope