Diferentes shebangs para Linux: guía completa y práctica

Última actualización: 27/02/2026
Autor: Isaac
  • El shebang «#!» indica al kernel qué intérprete ejecutará el script, pudiendo usar shells como bash, sh o lenguajes como Python y Perl.
  • Elegir entre /bin/sh, /bin/bash o /usr/bin/env depende de si se busca compatibilidad POSIX, extensiones de bash o mayor portabilidad.
  • La efectividad del shebang cambia según se invoque el script explícitamente, como ejecutable o con «.»/source, influyendo en subshells y entorno.
  • Las redirecciones POSIX, tuberías y operadores específicos de bash permiten controlar entrada, salida y errores de los procesos en los scripts.

Shebang en scripts de Linux

Cuando empiezas a escribir scripts en GNU/Linux es muy fácil perderse con la famosa primera línea que empieza por #!, el llamado shebang que indica qué intérprete ejecutará el script. Y claro, en cuanto ves ejemplos con /bin/bash, otros con /bin/sh, algunos con /usr/bin/env python o incluso líneas más raras como #!/bin/sh –, la duda aparece: ¿qué pongo yo en mis scripts y por qué?

En las siguientes líneas vamos a desmenuzar a fondo el concepto de shebang, los distintos intérpretes disponibles en Linux, cuándo usar cada variante y qué buenas prácticas seguir. También veremos cómo se relaciona con POSIX, con distribuciones como Debian o Ubuntu, con la forma de invocar scripts y con lenguajes como Python, Perl o AWK, de manera que tengas una visión global y práctica.

manual de bash
Artículo relacionado:
Manual de Bash: guía completa de scripting en Linux

Qué es exactamente el shebang en Linux

El término shebang (o hashbang) es el nombre que se le da a la secuencia de caracteres «#!» colocada en la primera línea de un archivo de texto ejecutable en sistemas tipo Unix. Su única misión es indicarle al kernel qué programa debe utilizar como intérprete para leer y ejecutar el contenido de ese fichero.

Aunque visualmente parece un simple comentario, la combinación de «#!» seguida de una ruta absoluta a un ejecutable tiene un significado especial para el sistema. Cuando lanzas un script con permisos de ejecución, por ejemplo ./script.sh, el kernel lee la primera línea; si detecta el patrón #!, toma lo que viene a continuación como ruta del intérprete y construye internamente una llamada equivalente a ejecutar ese intérprete pasando el script como parámetro.

Desde el punto de vista del lenguaje, el carácter «#» sigue siendo el inicio de un comentario para shells como sh o bash, por lo que esa línea no se interpreta como código del propio script sino que solo tiene significado para el sistema operativo. Por eso, si no se encuentra en la primera línea, se considera un comentario normal y el kernel lo ignora completamente.

El mecanismo es general: se puede usar shebang con cualquier ejecutable interpretador, no solo con shells. Es habitual verlo con Python, Perl, AWK, Ruby u otros lenguajes de scripting, lo que permite invocar el fichero directamente sin tener que escribir el comando del lenguaje cada vez.

Cómo actúa el sistema operativo al ejecutar un script con shebang

Cuando un archivo de texto tiene permisos de ejecución y lo llamas con ./nombre_script argumento1 argumento2, el kernel sigue una secuencia muy concreta: lee la primera línea del fichero, detecta el «#!», identifica la ruta del intérprete y lanza ese programa pasándole el script y sus argumentos.

En la práctica, si tienes un fichero ejecutable llamado programa cuya primera línea es #!/usr/bin/awk -f, al ejecutar ./programa arg1 arg2 en realidad el sistema lanza algo equivalente a /usr/bin/awk -f ./programa arg1 arg2. Esa traducción la hace el propio kernel de forma transparente, de modo que tú solo ves que el archivo se ejecuta.

Este mismo mecanismo se aplica a otros lenguajes: si el script contiene #!/usr/bin/env python, el sistema ejecutará el comando «/usr/bin/env python» pasando el script como primer argumento. Env se encarga de buscar el intérprete de Python en el PATH del usuario, lo que hace que este enfoque sea más portable entre sistemas con rutas distintas.

Es importante destacar que esta característica forma parte del comportamiento de los sistemas Unix y Linux. En entornos como MS Windows, donde el sistema asocia la ejecución a la extensión del archivo (por ejemplo, .exe), la línea con «#!» se ignora salvo que estés usando capas de compatibilidad o entornos específicos como Cygwin o WSL.

Intérpretes de comandos y familias de shells

El shebang se apoya directamente en la existencia de los distintos intérpretes de comandos o shells que hay instalados en un sistema GNU/Linux. Un shell es el programa que actúa de intermediario entre el usuario y el sistema, procesando los comandos, variables, funciones y estructuras de control que le indiquemos, ya sea interactivamente o a través de un script.

En el universo Unix existen varias familias de shells con sintaxis similar en su interior. La familia más extendida es la del Bourne Shell (sh), que dio lugar a derivados como bash, dash, ksh, zsh o ash. Estos shells comparten gran parte de su sintaxis básica, especialmente aquella definida por el estándar POSIX, aunque cada uno incorpora extensiones propias.

Dentro de esta familia, bash (Bourne Again Shell) es el shell por defecto en la mayoría de distribuciones Linux. Ofrece muchas funcionalidades adicionales (historial avanzado, autocompletado, arrays, estructura select, operadores extra, etc.) respecto al Bourne Shell original. Sus ficheros de configuración típicos para usuarios son ~/.bashrc y ~/.bash_profile.

Otro actor importante es dash (Debian Almquist Shell), un shell muy ligero y rápido, con menos características que bash pero más ajustado al estándar POSIX. En Debian y Ubuntu, por ejemplo, /bin/sh suele ser un enlace simbólico a /bin/dash, precisamente para que los scripts del sistema (como los de arranque) se beneficien de su rapidez y menor consumo.

También encontramos ksh (Korn Shell), centrado en funciones avanzadas de programación de scripts que pueden competir en algunos escenarios con herramientas como awk o perl. Y, en otra familia distinta, está csh (C Shell) y su derivado tcsh, que se caracterizan por una sintaxis parecida al lenguaje C pero con un uso bastante menor que los Bourne-like.

  Hotpatching en Windows Server: guía práctica, ciclo, costes y orquestación

El papel de /bin/sh y el estándar POSIX

Una de las claves para no liarse con los distintos shebangs es entender qué representa realmente /bin/sh en cada sistema y qué pinta aquí el estándar POSIX. Históricamente, el Bourne Shell original se llamaba /bin/sh y estaba disponible en todas las variantes de Unix, hasta el punto de convertirse en un estándar de facto.

El IEEE tomó esta realidad como base para definir la especificación POSIX 1003.2 (ISO 9945.2), que describe un lenguaje de comandos estándar. La mayor parte de los shells de la familia Bourne (bash, dash, ksh, etc.) implementan este estándar, añadiendo a partir de ahí extensiones particulares. Gracias a ello, un script escrito siguiendo las reglas POSIX para sh suele poder ejecutarse sin problemas en cualquiera de estos shells compatibles.

En sistemas GNU/Linux modernos, ya no existe el Bourne Shell original, sino implementaciones compatibles con él. La ruta /bin/sh se mantiene como un enlace simbólico a uno de esos shells. En algunas distribuciones apunta a /bin/bash, mientras que en Debian y Ubuntu suele apuntar a /bin/dash, decisión motivada por el deseo de que los scripts del sistema (#!/bin/sh) se ejecuten con un intérprete más rápido y ligero.

La consecuencia práctica para ti es clara: si tu shebang es #!/bin/sh y escribes el script respetando POSIX, deberías poder ejecutarlo correctamente tanto con dash como con bash o ksh. Si en cambio aprovechas extensiones propias de bash (como ciertos tipos de bucles, arrays o operadores) (por ejemplo para scripts con menús de opciones), deberías usar explícitamente #!/bin/bash o un equivalente basado en env.

Por eso muchas guías recomiendan que los scripts de sistema y de uso general usen #!/bin/sh con sintaxis POSIX, mientras que los scripts personales o de usuario que dependen de características concretas de bash indiquen claramente /bin/bash en la línea del shebang.

Ejemplos de shebang para distintos intérpretes

A partir de lo anterior, es fácil entender por qué encontramos diferentes variantes de shebang. Los más frecuentes para shells en Linux son líneas como #!/bin/bash, #!/bin/dash, #!/bin/zsh, #!/bin/tcsh o #!/bin/csh. Cada una indica que el script debe ser leído por un shell distinto, con sus propias particularidades sintácticas.

En muchos sistemas, bash se instala por defecto en /bin/bash, así que la línea:

#!/bin/bash

hace que el kernel invoque ese ejecutable concreto. Es la opción habitual cuando quieres usar capacidades específicas de bash como arrays indexados de forma nativa, el bucle for (( )), la estructura select y un largo etcétera de extensiones que no están presentes en un sh POSIX mínimo.

También puedes encontrarte con shebang como #!/usr/bin/perl, #!/usr/bin/env python3 o #!/usr/bin/env awk. En estos casos, el script no está pensado para ser leído por un shell sino por otros lenguajes de scripting. La filosofía es la misma: la primera línea indica qué programa se usará para interpretar el contenido del archivo.

Con AWK, por ejemplo, un script ejecutable que empiece con:

#!/usr/bin/awk -f

será tratado por el sistema como un archivo de comandos AWK y se ejecutará como si hubieras llamado directamente a /usr/bin/awk -f script.awk. El patrón es idéntico para Perl, Python y otros lenguajes habituales en entornos Unix.

Shebangs típicos en Bash y Shell Script: pros y contras

Uno de los dilemas más frecuentes al escribir scripts es elegir entre #!/usr/bin/env bash, #!/bin/bash, #!/bin/sh o variantes similares. No existe una respuesta única que valga para todo, pero sí criterios razonables para cada caso.

Cuando usas #!/bin/bash estás fijando de forma directa la ruta absoluta al intérprete. Esto es simple, predecible y funciona bien en la mayoría de distribuciones GNU/Linux de escritorio o servidor, donde bash suele estar disponible en esa ubicación. La desventaja es que en algunos entornos más exóticos o minimalistas esa ruta podría no existir.

Por otro lado, #!/usr/bin/env bash delega en el programa env la tarea de localizar el binario de bash en el PATH del usuario. Este enfoque es más portable entre sistemas distintos (por ejemplo, en macOS, BSD o instalaciones personalizadas) porque no asume una ruta fija, sino que confía en que bash esté accesible en el PATH. A cambio, depende de que /usr/bin/env sí exista, algo casi universal pero no absolutamente garantizado.

En cuanto a #!/bin/sh, la idea es justo la contraria: no forzar bash, sino declarar que el script cumple el estándar POSIX y puede ejecutarse con el shell «por defecto» del sistema. En Debian y Ubuntu esto será dash; en otras distribuciones puede ser bash u otro shell. Es la opción recomendada cuando buscas máxima compatibilidad, rapidez y adhesión al estándar, siempre que te limites a la sintaxis POSIX.

La variante #!/bin/sh - añade un matiz: ese guion puede servir para que el intérprete arranque con ciertas opciones, por ejemplo no cargando ficheros de inicio interactivos o activando modos específicos (según el shell concreto). Es menos común en scripts corrientes, pero puede verse en contextos muy controlados.

Diferencias entre sintaxis POSIX y extensiones de bash

Un punto clave para escoger bien el shebang es saber qué sintaxis estás usando realmente en tu script. Dos ejemplos ilustran muy bien la diferencia entre escribir en POSIX puro o depender de extensiones de bash.

Un bucle for totalmente POSIX compatible podría ser algo así:

#!/bin/sh
for VAR in 0 1 2 3
do
   echo "$VAR"
done

Este tipo de construcción es entendida sin problemas por sh, dash, bash y cualquier shell que implemente el estándar POSIX. Lo lógico es acompañarlo de un shebang genérico como #!/bin/sh, de modo que pueda aprovechar el shell que el sistema crea conveniente.

En cambio, bash ofrece un estilo de bucle numérico más cercano a lenguajes tipo C:

#!/bin/bash
for (( VAR=0; VAR<4; VAR++ ))
do
   echo "$VAR"
done

Esta sintaxis con for (( )) no forma parte del estándar POSIX y no es comprendida por shells mínimos como dash. Si ejecutas este script con /bin/dash script_bash.sh obtendrás errores de sintaxis, mientras que con /bin/bash script_bash.sh funcionará perfectamente.

  Cómo Crear Un Archivo En El Símbolo Del Sistema En Windows

Por eso, cada vez que uses funcionalidades específicas de bash deberías declararlo claramente en el shebang, en vez de usar #!/bin/sh. De lo contrario, tu script podrá fallar silenciosamente en sistemas que utilicen un shell POSIX estricto para sh.

Cómo influye el shebang según el modo de invocar un script

El efecto del shebang no es el mismo en todas las formas de invocar un script. Dependiendo de si llamas al script explícitamente mediante un shell, lo ejecutas como archivo o lo «importas» con el punto, el comportamiento cambia.

Si usas invocación explícita, por ejemplo:

/bin/sh script_ejemplo.sh
/bin/dash script_ejemplo.sh
/bin/bash script_ejemplo.sh

el shebang se ignora. El shell que has escrito al principio del comando es el que se usará para interpretar el script, sea cual sea la primera línea del archivo. De esta manera puedes probar un mismo script con distintos shells para ver si cumple el estándar POSIX o si aprovecha extensiones de uno concreto.

Con invocación implícita, cuando lanzas directamente ./script_ejemplo.sh tras haberle dado permisos de ejecución, el kernel sí mira la línea del shebang para decidir qué programa ejecutará el contenido. En este caso se crea un subshell o proceso hijo del shell actual que será el intérprete que lea el script.

Existe además la invocación con punto (.) o source en bash, tal que:

. script_ejemplo.sh

En este modo, el script no se ejecuta en un proceso hijo sino en el mismo shell actual. Esto significa que las variables, funciones y cambios de entorno que haga el script afectarán directamente a tu sesión actual. En ese caso, el shebang también se ignora, porque no se lanza un nuevo intérprete.

Todo esto tiene consecuencias prácticas importantes: según cómo invoques el script, el usuario efectivo y los permisos del proceso que lo ejecuta pueden cambiar o no. Si llamas a un script desde un shell con usuario normal, el proceso hijo heredará ese usuario y no podrá, por ejemplo, modificar ficheros protegidos como /etc/passwd, a menos que se fuerce otra cosa con mecanismos como su -c o similares.

Uso del shebang en scripts reales

Al crear un script desde cero en Linux, lo habitual es empezar siempre por la línea de shebang que indique claramente el intérprete que quieres utilizar. Por ejemplo, si estás escribiendo un script sencillo en bash para mostrar un banner, podrías crear un archivo mi_script.sh así:

#!/bin/bash
echo "Contenido de mi script"

Con el archivo guardado, el siguiente paso es darle permisos de ejecución con un comando como chmod +x mi_script.sh. A partir de ese momento puedes ejecutarlo simplemente con ./mi_script.sh desde el directorio donde se encuentre, siempre que tu PATH y permisos te lo permitan.

Si prefieres usar un shell POSIX estricto, puedes cambiar la primera línea a #!/bin/sh y escribir el contenido del script de forma compatible. Esto es especialmente útil en scripts que quieras reutilizar en muchos sistemas distintos, incluyendo entornos de arranque o scripts bajo /etc/init.d/ donde se suele emplear este enfoque.

Una alternativa muy extendida, sobre todo en lenguajes como Python, es usar #!/usr/bin/env python3. Aquí la idea es dejar que env busque el ejecutable de Python 3 en el PATH y lo lance. Esto evita depender de que el intérprete esté exactamente en /usr/bin/python3, algo que puede variar según la distribución o el entorno.

Del mismo modo, puedes tener scripts en Perl, AWK o incluso en shells menos habituales, siempre y cuando la ruta (o el comando con env) que pongas en la línea del shebang apunte a un ejecutable real existente en el sistema donde se vaya a correr.

Buenas prácticas al elegir y escribir el shebang

Para que tus scripts sean manejables, mantenibles y portables, conviene seguir una serie de buenas prácticas a la hora de escribir la línea de shebang y configurar los permisos. Son detalles sencillos que evitan muchos dolores de cabeza más adelante.

Lo primero es indicar siempre el intérprete adecuado para el lenguaje o shell que estés utilizando. Si el script está escrito en bash y usa extensiones específicas, no pongas #!/bin/sh; si es Python 3, no uses simplemente python si en tu sistema ese comando lanza Python 2. Ajusta la línea para reflejar la realidad del código.

Como norma general, es preferible usar rutas absolutas en el shebang, por ejemplo /bin/bash o /usr/bin/python3, para evitar ambigüedades. Sin embargo, cuando quieres máxima portabilidad entre sistemas heterogéneos, la técnica de /usr/bin/env resulta muy útil, ya que busca el intérprete en el PATH y se adapta mejor a entornos donde no controlas la instalación exacta.

Otro punto esencial es recordar siempre hacer ejecutables los archivos de script con chmod +x. Aunque puedes invocarlos llamando explícitamente al intérprete (por ejemplo bash script.sh), otorgarles permiso de ejecución permite que se comporten como cualquier otro comando del sistema, especialmente si añades su directorio a tu PATH (por ejemplo ~/scripts).

Desde el punto de vista organizativo, es muy recomendable guardar tus scripts en un directorio dedicado, como ~/bin o ~/scripts, y añadirlo al PATH del usuario. Así evitas tener archivos ejecutables desperdigados y consigues una experiencia similar a la de usar comandos «oficiales».

Finalmente, aunque no está directamente relacionado con el shebang, comentar adecuadamente el código dentro del script facilita su comprensión futura. Añadir comentarios sobre qué hace el script, qué asunciones hace sobre el entorno y qué sintaxis específica de shell utiliza ayuda a decidir rápidamente qué shebang es el más apropiado si en algún momento tienes que modificarlo.

Redirecciones, descriptores y su relación con el shell

Para entender bien el trabajo de los shells y, por extensión, de muchos scripts que usan shebang, conviene repasar cómo Linux asocia recursos del sistema a ficheros y descriptores. En este modelo, casi todo se expone como un archivo: directorios, dispositivos, sockets, procesos, pseudo-ficheros en /proc o /dev, etc.

  Cómo convertir un vídeo a GIF en el iPhone y el iPad

Cuando un proceso quiere leer o escribir en un recurso, debe abrir el fichero correspondiente con una llamada al sistema, obteniendo un descriptor de fichero que es simplemente un número entero. Ese número identifica la asociación entre el proceso y el recurso. Cada proceso tiene su propia tabla de descriptores, accesible por ejemplo a través de /proc/PID/fd/.

Por convención, cualquier proceso tiene normalmente asociados tres descriptores especiales: 0 (entrada estándar), 1 (salida estándar) y 2 (salida de error estándar). El shell que usas en la terminal hace que el descriptor 0 apunte al teclado, mientras que 1 y 2 apuntan a la pantalla. La mayoría de comandos POSIX están escritos para leer de la entrada estándar (descriptor 0) y escribir en la salida estándar (1) o de errores (2).

Cuando lanzas un comando desde un shell, el proceso hijo hereda la asociación de estos descriptores 0, 1 y 2 del proceso padre, salvo que se haga algo explícito para cambiarlos. De aquí nace la potencia de las redirecciones: puedes pedir al shell que reasigne esos descriptores a ficheros u otros recursos antes de lanzar el proceso hijo.

Para modificar los descriptores del propio shell actual se usa el comando exec, permitiendo asociar un descriptor a un fichero para lectura, escritura o ambas cosas, duplicar descriptores o cerrarlos. Por ejemplo, exec 4< /tmp/fichero vincula el descriptor 4 del shell con /tmp/fichero para lectura, de forma que más tarde puedas hacer ls >&4 para enviar la salida de ls a ese descriptor.

Redirecciones POSIX en comandos y scripts con shebang

A nivel de comandos individuales (y por tanto dentro de cualquier script sea cual sea su shebang), las redirecciones POSIX permiten cambiar de forma declarativa qué fichero o recurso se asocia a cada descriptor en el proceso hijo. La sintaxis básica es:

comando op fichero_o_descriptor

donde n es el descriptor (0, 1, 2, etc.), op es el operador de redirección (<, >, >>, <&, >&, etc.) y fichero_o_descriptor es la ruta o descriptor objetivo. Si omites n, se toman valores por defecto (0 para entrada, 1 para salida).

Las redirecciones de entrada (<) hacen que el comando lea desde un fichero en vez de desde la entrada estándar. Por ejemplo, cat < fichero consigue que «fichero» se convierta en la entrada estándar de cat, que seguirá escribiendo en la salida estándar (pantalla).

Las redirecciones de salida (> y >>) envían la salida estándar a un fichero, truncando su contenido anterior (>) o añadiendo al final (>>). Combinadas con 2> o 2>&1, permiten redirigir también los mensajes de error. Es muy habitual en scripts con shebang ver líneas del estilo ls -l /bin/bash ./script > fichero 2>&1 para agrupar salida normal y de error en un mismo archivo.

Existen también los llamados Here-Documents, que se escriben con << delimitador y permiten introducir texto empotrado directamente en el propio script. Todo lo que escribas hasta el delimitador se convierte en la entrada estándar del comando. Por ejemplo:

cat << END > fichero

hará que todo lo tecleado hasta la línea que contenga solo END se guarde en fichero. Esta técnica se usa mucho dentro de scripts con shebang para generar archivos de configuración o bloques de texto largos sin tener que crear ficheros temporales a mano.

Uso de tuberías y operadores específicos de Bash

Otro mecanismo clave es la tubería o pipeline, representada por el operador «|». Cuando escribes algo como comando1 | comando2, el shell asocia la salida estándar de comando1 con la entrada estándar de comando2, de forma que la información fluye de un proceso al otro sin pasar por archivos intermedios.

Este patrón está tan asumido que se usa casi sin pensar: ls | more envía el listado producido por ls a more, que lo presenta por pantalla paginándolo. En un script con un shebang POSIX o de bash la semántica es la misma; lo único que cambia es qué shell interpreta la tubería.

Además de los operadores definidos por POSIX, bash añade algunos atajos propios para redirecciones combinadas. Por ejemplo, cmd &> fichero o cmd >& fichero hacen que tanto la salida estándar como la de error se redirijan al mismo fichero, equivalentes a cmd > fichero 2>&1. Estas formas abreviadas no son portables a todos los shells POSIX, así que si las usas deberías asegurarte de que el shebang apunte explícitamente a bash.

Uno de los detalles más finos al trabajar con redirecciones en scripts es el orden. El shell analiza las redirecciones de izquierda a derecha antes de ejecutar el comando. Cambiar su posición puede alterar el resultado de forma significativa, como se aprecia en ejemplos del tipo ls /tmp 2> file 1>&2 frente a 1>&2 ls /tmp 2> file.

Cuando quieres descartar información por completo, es clásico recurrir al fichero nulo /dev/null, que actúa como un «agujero negro» para la salida. Por ejemplo, ls -l /usr > /dev/null 2>&1 hace que la salida estándar y la de errores desaparezcan, algo muy habitual para scripts que no deben mostrar nada salvo fallo crítico.

En conjunto, entender bien el concepto de shebang, las diferencias entre /bin/sh y /bin/bash, el papel de POSIX, los distintos intérpretes disponibles y las posibilidades de redirección y tuberías te permite escribir scripts mucho más robustos y portables. Si eliges conscientemente la línea inicial, respetas la sintaxis adecuada para cada shell y cuidas el entorno de ejecución, tus scripts se comportarán de manera predecible en la mayoría de sistemas GNU/Linux y Unix, desde sencillos guiones en tu carpeta personal hasta complejas rutinas de arranque del sistema.