#! ¿Por qué hay scripts con hashtag?

#! Shebang: los scripts que usan hashtag

Wikipedia

En algún momento habrás visto algún script que empieza con algo parecido a #!/usr/bin/bash o #!/usr/bin/python3, y puede que hayas comprobado que, al ejecutar el script, el resultado no se ve alterado con o sin esa primera línea de código.

Os pongo un ejemplo, imaginemos un archivo llamado hello_world.py:

#!/usr/bin/python3 print("Hello, world!")

Al ejecutar el script, vemos que imprime en la terminal el texto Hello, world!

$ python3 hello_world.py Hello, world!

Sin embargo, si eliminamos la primera línea del código y lo volvemos a ejecutar, no notaremos ninguna diferencia.

Hagamos el ejemplo con nuevo archivo llamado hello_friend.py:

print("Hello, friend!")
$ python3 hello_world.py Hello, friend!

¿Qué sentido tiene usar !#? ¿Qué es y para qué sirve?

Respuesta corta:

El nombre que recibe es shebang y su función es que el propio script indique al sistema operativo con qué intérprete debe ejecutarse.

¿Lo cualo?

Respuesta larga para principiantes

Entender qué es y como usar un shebang no es para nada difícil, pero sí necesitarás concer algunos conceptos básicos.

¡Pero tranqui! Por eso estoy aquí, para que puedas aprender mientras te tomas un buen café (con bits ☕).

Dos tipos de lenguajes

Sin entrar al detalle, podemos dividir los tipos de lenguajes de programación en dos secciones: los interpretados y los compilados.

Los detalles serían para otro post, por ahora solo quiero que entiendas lo siguiente:

  • Los lenguajes compilados se pueden ejecutar gracias a un tipos de programa llamado compilador
  • Los lenguajes interpretados se pueden ejecutar gracias a un tipo de programa llamado intérprete

Si quieres saber algo más sobre la diferencia entre ambos tipos de lenguajes, tengo un post dedicado a ello: Lenguajes interpretados vs compilados.

Lo primero que debes saber sobre el shebang (#!) es que solo se usa en los lenguajes interpretados, es decir, aquellos que se ejecutan mediante un intérprete.

Los comentarios en los intérpretes

Todos los lenguajes de programación tienen alguna manera de escribir comentarios en el código. Cómo se escriban dependerá del lenguaje.

Por ejemplo, para comentar una línea de código en JavaScript se usa //, mientras que en Python se usa #.

Pero Python no es el único lenguaje que usa # para los comentarios, también pasa en lenguajes como Bash, Ruby, Perl y otros.

¿Qué tienen en común estos lenguajes? Exacto, que todos son interpretados.

Por lo tanto, el símbolo # nos sirve para comentar una línea de código en los lenguajes interpretados.

Shebang es un comentario en el código

Ahora ya sabemos que todo lo que haya después del símbolo # es un comentario y el intérprete lo va a ignorar.

Por lo tanto, cualquier shebang no deja de ser un comentario a ojos de cualquier lenguaje de programación.

Es decir, en el ejemplo hello_world.py del principio, la primera línea del script (#!/usr/bin/python3) no será leída ni ejecutada por el intérprete de Python.

Y éste es el motivo de que el shebang no afecta en nada a la ejecución del script cuando lo ejecutamos desde su intérprete.

A quién va dirigido el shebang

El shebang es un mensaje que no va dirigido al intérprete, sino al sistema operativo.

Por eso empieza con #, para que no pueda ser leído por el intérprete pero sí por el sistema operativo.

Lo habitual es que se use en sistemas de tipo UNIX, pero eso ya es tema para otro post.

Lo que el shebang está indicando al sistema operativo es a qué intérprete debe poner en marcha para ejecutar el resto del script. Y eso lo hace mediante la ruta donde está almacenado (que es el resto del texto que hay en la línea del shebang, en el ejemplo sería /usr/bin/python3).

Pero solo funciona en archivos ejecutables.

Archivos ejecutables

Al escribir un script, lo que hacemos es crear un archivo normal y añadirle código. Este tipo de archivo puede ser leído y escrito, así como también eliminado. Pero no puede ser ejecutado.

El sistema operativo solo puede ejecutar archivos "ejecutables" (valga la redundancia).

Es decir, son un tipo de archivo que el sistema operativo tiene el permiso de poner en marcha (como, por ejemplo, los diferentes comandos o cualquier instalador).

Recuerda que los scripts que hemos usado con los ejemplos anteriores no son ejecutbles, y por ese motivo debemos ejecutarlos desde el intérprete.

Es decir, que realmente lo que hacemos es ejecutar el intérprete, y decirle a éste qué archivo queremos que lea.

El proceso que sigue el sistema operativo al leer un script que usa shebang

  1. Ordenamos al sistema operativo que ejecute el archivo
  2. El sistema comprueba que el archivo sea ejecutable. En caso de que no lo fuese, detendría la ejecución.
  3. Al comprobar que es ejecutable, lee la primera línea buscando el #!. Al encontrarlo, lee la ruta del intérprete que sigue al shebang.
  4. Ejecuta el intérprete de la ruta. En caso de que no hubiera ningún intérprete en esa ruta, detendría la ejecución mostrando un error.
  5. El sistema le pasa el script al intérprete para que lo lea y lo ejecute.

Explicado con ejemplos siempre es mejor

Dejo aquñi unos ejemplos que podrás ejecutar en tu PC, aunque necesitarás usar Linux y tener Python3 instalado.

Lo primero será abrir una terminal (Ctrl + Alt + T).

Una vez abierta, vamos a comprobar dónde está almacenado el intérprete de Python. Para ello usaremos el comando where:

$ where python3 /usr/bin/python3 /bin/python3

Puede que el resultado no sea idéntico al mío, no te preocupes, no es ningún problema.

Si observas, la primera respuesta del comando, /usr/bin/python3, coincide con el shebang del primer ejemplo, #!/usr/bin/python3.

Para ejecutar un script en Python normalmente usaremos el comando python3 seguido del nombre del archivo. En el primero ejemplo he usado python3 hola_mundo.py.

Pero también podemos conseguir el mismo resultado llamando al intérprete desde su ruta.

Prueba de crear el archivo hola_mundo.py:

print("¡Hola, mundo!")

Y ahora ejecútalo con los dos métodos: el comando de python y la ruta del intérprete:

$ python3 hola_mundo.py ¡Hola, mundo!
$ /usr/bin/python3 hola_mundo.py ¡Hola, mundo!

¡Mismo resultado!

Pero ambos casos tiene un problema: para ejecutar el script necesitamos llamar a su intérprete.

Por ahora no es un gran problema, son scripts sencillos, pero ¿y si queremos ejecutar el script sin preocuparnos de en qué lenguaje está escrito, o de tener que usar el intérprete adecuado?

Aquí es donde entra el shebang, ya que éste nos permite poder escribir un script y luego ponerlo en marcha sin tener que llamar manualmente a ningún intérprete.

Vamos a crear un nuevo archivo al que llamaremos hola_amigo.py, y en este caso le añadiremos el shebang:

#!/usr/bin/python3 print("¡Hola, amigo!")

Por ahora este archivo es normal, así que deberemos usar el intérprete de Python para ejecutarlo.

Para que sea un archivo ejecutable, será necesario añadirle permisos de ejecución. Para ello usa el comando chmod:

$ chmod +x hola_amigo.py

Ahora el archivo puede ser ejecutado por el sistema operativo.

Puedes seguir usando el intérprete si lo prefieres, pero no ya no es necesario al incluir el shebang en el código.

Ahora, el propio sistema operativo no solo puede ejecutar el archivo, además puede saber qué intérprete debe poner en marcha para leer el resto del archivo:

$ ./hola_amigo.py ¡Hola, amigo!

¡Pero no solo eso! ¡Ya no necesitamos usar la extensión .py!

Con el uso del shebang hemos delegado al sistema la responsabilidad de escoger el intérprete adecuado, y por lo tanto no necesitamos indicar a nadie ni a nada el lenguaje con el que ha sido escrito el script.

Una prueba sencilla es copiando el archivo:

$ cp hola_amigo.py hola_amigo

El nuevo archivo hola_amigo funciona igual que el original y no necesita de ninguna extensión.

Comentarios

Entradas populares de este blog

¿Terminal o Shell? Qué son y en qué se diferencian

Café con Bits 7 ☕ Motivación: hacer un videojuego

Zoom: el algoritmo de los puntos de fuga