Desarrollador web | Entusiasta del hacking | Diseñador UI

Cómo ejecutar scripts en Linux: ./script.sh, bash script.sh, sh script.sh y source

Ejecutar un script en Linux parece algo sencillo: escribes un comando, pulsas Enter y esperas que funcione.

Pero en realidad no siempre ocurre lo mismo.

No es igual ejecutar:

./script.sh

que ejecutar:

bash script.sh

o:

sh script.sh

o incluso:

source script.sh

Aunque todos estos comandos pueden parecer formas equivalentes de “lanzar un script”, internamente tienen diferencias importantes. Cambia el intérprete que se utiliza, cambia cómo se leen los permisos, cambia si se tiene en cuenta el shebang y cambia si las variables del script afectan o no a tu terminal actual.

Entender estas diferencias es fundamental si trabajas con Linux, Bash, automatización, servidores, despliegues, Docker, cron jobs o scripts de mantenimiento.

En esta guía vamos a ver, con ejemplos reales, qué ocurre en cada caso.


Qué es un script en Linux

Tabla del contenido

Un script es un archivo de texto que contiene una serie de instrucciones que serán interpretadas por un programa.

Por ejemplo, este archivo llamado saludo.sh:

#!/bin/bash

echo "Hola desde Linux"

Contiene una instrucción sencilla:

echo "Hola desde Linux"

Pero esa línea no se ejecuta sola. Linux necesita saber qué programa debe interpretar ese archivo.

Ese programa puede ser:

bash
sh
python3
perl
node

u otro intérprete.

Por eso en muchos scripts aparece una primera línea especial:

#!/bin/bash

A esa línea se le llama shebang.


El ejemplo base

Vamos a crear un script sencillo para probar las distintas formas de ejecución.

Archivo:

nano script.sh

Contenido:

#!/bin/bash

echo "Directorio actual: $(pwd)"
echo "Usuario actual: $(whoami)"
echo "Shell usado: $SHELL"

Guardamos el archivo y comprobamos sus permisos:

ls -l script.sh

Puede que veas algo parecido a esto:

-rw-r--r-- 1 david david 95 ene 10 10:30 script.sh

La parte importante es esta:

-rw-r--r--

Ese archivo se puede leer y escribir, pero todavía no tiene permiso de ejecución.


Forma 1: ejecutar con ./script.sh

La forma más típica de ejecutar un script en Linux es:

./script.sh

Pero para que esto funcione, el archivo necesita permiso de ejecución.

Si intentas ejecutarlo sin ese permiso, puedes obtener este error:

bash: ./script.sh: Permission denied

Para solucionarlo:

chmod +x script.sh

Ahora sí:

./script.sh

Salida esperada:

Directorio actual: /home/david
Usuario actual: david
Shell usado: /bin/bash

Qué significa ./script.sh

El punto representa el directorio actual:

.

La barra indica que queremos acceder a algo dentro de ese directorio:

/

Por tanto:

./script.sh

significa:

Ejecuta el archivo script.sh que está en el directorio actual.

Esto es necesario porque, por seguridad, Linux normalmente no busca ejecutables en el directorio actual a menos que se lo indiques explícitamente.

Por eso esto puede fallar:

script.sh

aunque el archivo exista.

En cambio, esto sí apunta directamente al archivo:

./script.sh

Qué ocurre internamente al ejecutar ./script.sh

Cuando ejecutas:

./script.sh

Linux hace varias comprobaciones:

  1. Comprueba que el archivo existe.
  2. Comprueba que tienes permiso de ejecución.
  3. Lee la primera línea del archivo.
  4. Si encuentra un shebang, usa ese intérprete.
  5. Ejecuta el script en un nuevo proceso.

Si el archivo empieza así:

#!/bin/bash

Linux usará:

/bin/bash

para interpretar el archivo.

Es decir, esto:

./script.sh

acaba siendo conceptualmente parecido a esto:

/bin/bash ./script.sh

Pero con una diferencia importante: en el primer caso, Linux usa el shebang para decidir el intérprete.


Forma 2: ejecutar con bash script.sh

Otra forma habitual es:

bash script.sh

En este caso estás diciendo explícitamente:

Usa Bash para interpretar este archivo.

Aquí no necesitas permiso de ejecución.

Aunque el archivo tenga estos permisos:

-rw-r--r--

puedes ejecutarlo con:

bash script.sh

porque no estás ejecutando directamente el archivo. Estás ejecutando el programa bash y le estás pasando el archivo como argumento.


Diferencia clave entre ./script.sh y bash script.sh

Con:

./script.sh

Linux mira el shebang:

#!/bin/bash

Con:

bash script.sh

el shebang pierde importancia, porque ya has elegido tú el intérprete.

Por ejemplo, imagina este script:

#!/bin/sh

echo "Hola"

Si ejecutas:

./script.sh

se usará:

/bin/sh

Pero si ejecutas:

bash script.sh

se usará Bash, aunque el archivo diga #!/bin/sh.

Esto puede cambiar el comportamiento del script.


Forma 3: ejecutar con sh script.sh

También puedes ejecutar:

sh script.sh

Pero aquí hay que tener cuidado.

sh no siempre es lo mismo que bash.

En muchos sistemas Linux, /bin/sh apunta a otro shell más pequeño o más estricto, como dash.

Puedes comprobarlo con:

ls -l /bin/sh

En algunas distribuciones verás algo parecido a:

/bin/sh -> dash

Eso significa que cuando ejecutas:

sh script.sh

no necesariamente estás ejecutando Bash.


Problema típico con sh script.sh

Este script funciona en Bash:

#!/bin/bash

nombre="David"
echo "Hola, ${nombre^^}"

La expresión:

${nombre^^}

convierte el texto a mayúsculas en Bash.

Si ejecutas:

bash script.sh

puede funcionar:

Hola, DAVID

Pero si ejecutas:

sh script.sh

puede fallar:

Bad substitution

¿Por qué?

Porque esa sintaxis es propia de Bash, no necesariamente compatible con sh.


Cuándo usar sh script.sh

Usa:

sh script.sh

solo si el script está escrito para ser compatible con POSIX Shell.

Por ejemplo:

#!/bin/sh

nombre="David"
echo "Hola, $nombre"

Este tipo de script evita características específicas de Bash.

Pero si tu script usa arrays, [[ ]], expansión avanzada de variables, funciones modernas o sintaxis propia de Bash, deberías ejecutarlo con Bash:

bash script.sh

o directamente con:

./script.sh

usando este shebang:

#!/bin/bash

Forma 4: ejecutar con source script.sh

La cuarta forma es diferente:

source script.sh

También se puede escribir como:

. script.sh

En este caso el script no se ejecuta en un proceso separado.

Se ejecuta dentro de la shell actual.

Esto cambia mucho las cosas.


Ejemplo con variables

Crea este archivo:

nano variables.sh

Contenido:

#!/bin/bash

MI_VARIABLE="Hola desde el script"

Ahora ejecútalo así:

bash variables.sh

Después intenta ver la variable:

echo "$MI_VARIABLE"

Probablemente no verás nada.

¿Por qué?

Porque la variable se creó dentro del proceso del script. Cuando el script terminó, ese proceso desapareció.

Ahora prueba:

source variables.sh

Y luego:

echo "$MI_VARIABLE"

Ahora sí verás:

Hola desde el script

Porque source ejecuta el contenido dentro de tu shell actual.


Cuándo usar source

source se usa cuando quieres que el script modifique el entorno actual.

Ejemplos típicos:

source ~/.bashrc
source .venv/bin/activate
source config.env

También se usa para cargar variables:

source variables.sh

o funciones:

source funciones.sh

Pero no deberías usar source para ejecutar cualquier script sin pensar.

Si el script contiene:

cd /tmp

y lo ejecutas con:

source script.sh

tu terminal cambiará realmente al directorio /tmp.

En cambio, si lo ejecutas con:

bash script.sh

el cambio de directorio solo ocurre dentro del proceso del script.


Comparativa rápida

ComandoUsa shebangNecesita chmod +xEjecuta en nueva shellAfecta la shell actual
./script.shNo
bash script.shNo realmenteNoNo
sh script.shNo realmenteNoNo
source script.shNoNoNo

Diferencia entre ejecutar y leer un script

Esto es importante:

./script.sh

ejecuta directamente el archivo.

Pero esto:

bash script.sh

ejecuta Bash y Bash lee el archivo.

Por eso en el primer caso el sistema necesita que el archivo tenga permiso de ejecución.

En el segundo caso, el archivo solo necesita permiso de lectura.

Puedes verlo así:

chmod -x script.sh

Ahora esto fallará:

./script.sh

Pero esto puede seguir funcionando:

bash script.sh

Porque Bash puede leer el archivo aunque no sea ejecutable.


Qué papel tiene el shebang

El shebang es la primera línea de muchos scripts:

#!/bin/bash

Sirve para indicar qué intérprete debe usarse cuando el archivo se ejecuta directamente.

Por ejemplo:

#!/bin/bash

usa Bash.

#!/bin/sh

usa sh.

#!/usr/bin/env bash

busca bash en el PATH.

#!/usr/bin/env python3

busca python3 en el PATH.

El shebang solo es realmente importante cuando ejecutas el archivo directamente:

./script.sh

No cuando haces:

bash script.sh

porque ahí ya estás eligiendo Bash manualmente.

Artículo relacionado recomendado:

/linux/shebang-linux/

#!/bin/bash vs #!/usr/bin/env bash

Estas dos líneas son muy comunes:

#!/bin/bash

y:

#!/usr/bin/env bash

La primera usa una ruta fija.

La segunda busca Bash usando el entorno actual.

En sistemas Linux tradicionales, Bash suele estar en:

/bin/bash

Pero en otros entornos puede estar en otra ubicación.

Por ejemplo:

/usr/local/bin/bash

Con:

#!/usr/bin/env bash

el sistema busca el ejecutable bash dentro del PATH.

Esto puede ser útil para portabilidad, pero también implica que el entorno puede influir en qué Bash se ejecuta.

Para scripts de sistema suele preferirse una ruta explícita.

Para scripts de usuario o proyectos portables, muchas veces se usa:

#!/usr/bin/env bash

Artículo satélite recomendado:

/linux/bin-bash-vs-usr-bin-env-bash/

Permisos de ejecución con chmod +x

Para ejecutar un script directamente con:

./script.sh

necesitas permiso de ejecución.

Se añade así:

chmod +x script.sh

Después puedes comprobarlo con:

ls -l script.sh

Antes:

-rw-r--r--

Después:

-rwxr-xr-x

La x indica permiso de ejecución.

También puedes asignar permisos de forma más explícita:

chmod 755 script.sh

Esto da permisos de lectura, escritura y ejecución al propietario, y lectura y ejecución al grupo y al resto.

Artículo relacionado recomendado:

/linux/chmod-x-permisos-ejecucion/

Errores comunes al ejecutar scripts en Linux

1. Permission denied

Error:

bash: ./script.sh: Permission denied

Causa probable:

El archivo no tiene permiso de ejecución.

Solución:

chmod +x script.sh
./script.sh

También puedes ejecutarlo sin cambiar permisos:

bash script.sh

2. bad interpreter: No such file or directory

Error típico:

bad interpreter: No such file or directory

Puede tener varias causas.

Una de las más comunes es que el shebang apunta a un intérprete que no existe:

#!/bin/bash

Comprueba si existe:

ls -l /bin/bash

Otra causa muy común es que el archivo tenga finales de línea de Windows.

En ese caso puedes ver errores como:

/bin/bash^M: bad interpreter

Ese ^M indica que el archivo tiene saltos de línea CRLF.

Solución:

dos2unix script.sh

O con sed:

sed -i 's/\r$//' script.sh

3. command not found

Error:

script.sh: command not found

Esto puede pasar si intentas ejecutar:

script.sh

sin indicar la ruta.

Solución:

./script.sh

O mueve el script a un directorio incluido en el PATH, por ejemplo:

/usr/local/bin

También puedes crear un directorio personal para scripts:

mkdir -p ~/bin

Y añadirlo al PATH en ~/.bashrc:

export PATH="$HOME/bin:$PATH"

Después:

source ~/.bashrc

4. Bad substitution

Error:

Bad substitution

Suele aparecer cuando ejecutas con sh un script que usa sintaxis de Bash.

Por ejemplo:

${variable^^}

Solución:

Ejecuta con Bash:

bash script.sh

o usa shebang de Bash:

#!/bin/bash

y luego:

chmod +x script.sh
./script.sh

Ejemplo práctico completo

Vamos a crear un script algo más realista.

Archivo:

nano backup.sh

Contenido:

#!/bin/bash

set -e

ORIGEN="$HOME/documentos"
DESTINO="$HOME/backups"

mkdir -p "$DESTINO"

FECHA=$(date +"%Y-%m-%d_%H-%M-%S")
ARCHIVO="backup_$FECHA.tar.gz"

tar -czf "$DESTINO/$ARCHIVO" "$ORIGEN"

echo "Backup creado en: $DESTINO/$ARCHIVO"

Damos permisos:

chmod +x backup.sh

Ejecutamos:

./backup.sh

Este script:

  1. Define un directorio de origen.
  2. Define un directorio de destino.
  3. Crea la carpeta de backups si no existe.
  4. Genera un nombre de archivo con fecha.
  5. Comprime el directorio.
  6. Muestra un mensaje final.

Qué pasaría si usamos bash backup.sh

También funcionaría:

bash backup.sh

Pero el shebang no sería tan relevante, porque hemos elegido Bash manualmente.


Qué pasaría si usamos sh backup.sh

Podría fallar si el script usa características propias de Bash.

En este caso concreto puede que funcione, pero no deberías asumirlo.

Si el script empieza con:

#!/bin/bash

lo correcto es ejecutarlo como script Bash:

./backup.sh

o:

bash backup.sh

Qué pasaría si usamos source backup.sh

No es recomendable.

El script se ejecutaría dentro de tu shell actual. Si modifica variables, rutas o el directorio actual, esos cambios permanecerían después de terminar.

source debería reservarse para scripts que cargan configuración, variables o funciones.


Buenas prácticas al escribir scripts ejecutables

Usa un shebang claro

Para Bash:

#!/bin/bash

o:

#!/usr/bin/env bash

Para Python:

#!/usr/bin/env python3

Activa errores estrictos cuando tenga sentido

En scripts Bash más serios, puedes usar:

set -euo pipefail

Esto ayuda a detectar errores antes.

Significa:

set -e

El script se detiene si un comando falla.

set -u

El script falla si usas variables no definidas.

set -o pipefail

El script detecta errores dentro de tuberías.

Ejemplo:

#!/bin/bash

set -euo pipefail

echo "Script seguro"

No siempre necesitas esto en scripts pequeños, pero es una buena práctica en automatizaciones importantes.


Usa comillas en variables

Mejor esto:

rm "$archivo"

que esto:

rm $archivo

Las comillas evitan problemas con espacios, caracteres especiales o variables vacías.

Ejemplo:

archivo="mi documento.txt"
cat "$archivo"

Comprueba argumentos

Ejemplo:

#!/bin/bash

if [ $# -lt 1 ]; then
echo "Uso: $0 archivo"
exit 1
fi

archivo="$1"

echo "Procesando: $archivo"

Aquí:

$#

representa el número de argumentos recibidos.

$0

representa el nombre del script.

$1

representa el primer argumento.


Usa códigos de salida

Un script debería devolver 0 si todo ha ido bien y un valor distinto de 0 si hubo un error.

Ejemplo:

#!/bin/bash

if [ ! -f "$1" ]; then
echo "El archivo no existe"
exit 1
fi

echo "El archivo existe"
exit 0

Esto es especialmente importante en automatizaciones, cron jobs, pipelines CI/CD y scripts que serán llamados por otros programas.


Cuándo usar cada forma

Usa ./script.sh cuando…

El script tiene shebang, permisos de ejecución y quieres ejecutarlo como programa.

Ejemplo:

./deploy.sh

Es la forma más limpia para scripts propios, herramientas internas y automatizaciones.


Usa bash script.sh cuando…

Quieres forzar que el script se ejecute con Bash o no quieres cambiar permisos.

Ejemplo:

bash instalar.sh

También es útil para probar scripts rápidamente.


Usa sh script.sh cuando…

El script es compatible con POSIX Shell y no depende de funciones específicas de Bash.

Ejemplo:

sh script-posix.sh

No lo uses a ciegas con scripts escritos para Bash.


Usa source script.sh cuando…

Quieres cargar variables, funciones o configuración en tu shell actual.

Ejemplo:

source .env
source ~/.bashrc
source .venv/bin/activate

No lo uses para ejecutar scripts de instalación o mantenimiento sin revisar antes qué hacen.


Relación con Python

Este mismo concepto también aplica a scripts de Python.

Ejemplo:

#!/usr/bin/env python3

print("Hola desde Python")

Si guardas el archivo como:

script.py

puedes darle permisos:

chmod +x script.py

y ejecutarlo:

./script.py

Linux leerá el shebang:

#!/usr/bin/env python3

y usará Python 3 para ejecutar el archivo.

También podrías ejecutarlo así:

python3 script.py

En ese caso, igual que con Bash, estás eligiendo el intérprete manualmente.

Artículo relacionado recomendado:

/python/scripts-python-linux/

Resumen técnico

Ejecutar scripts en Linux no es solo “lanzar un archivo”.

Cada forma tiene implicaciones distintas:

./script.sh

Ejecuta el archivo directamente, usa el shebang y requiere permisos de ejecución.

bash script.sh

Ejecuta Bash y le pasa el archivo como entrada. No requiere chmod +x.

sh script.sh

Ejecuta el script con sh, que puede no ser Bash. Puede fallar si el script usa sintaxis específica de Bash.

source script.sh

Ejecuta el contenido dentro de la shell actual. Puede modificar variables, funciones y directorio de trabajo de tu terminal.

La diferencia parece pequeña, pero en sistemas reales puede explicar muchos errores de permisos, intérpretes, variables, entornos virtuales y automatizaciones que no se comportan como esperabas.


Preguntas frecuentes

¿Por qué ./script.sh me da Permission denied?

Porque el archivo no tiene permiso de ejecución. Puedes solucionarlo con:

chmod +x script.sh
./script.sh

También puedes ejecutarlo con:

bash script.sh

si solo necesitas probarlo.


¿Por qué bash script.sh funciona pero ./script.sh no?

Porque bash script.sh solo necesita leer el archivo, mientras que ./script.sh necesita que el archivo tenga permiso de ejecución y un shebang correcto.


¿Es lo mismo sh script.sh que bash script.sh?

No necesariamente. En muchos sistemas, sh no es Bash. Puede ser dash u otro intérprete compatible con POSIX Shell. Si el script usa características propias de Bash, puede fallar con sh.


¿Para qué sirve source script.sh?

Sirve para ejecutar el contenido del script dentro de la shell actual. Es útil para cargar variables, funciones o configuraciones.

Ejemplos comunes:

source ~/.bashrc
source .env
source .venv/bin/activate

¿El shebang funciona cuando ejecuto bash script.sh?

No de la misma manera. Cuando ejecutas bash script.sh, estás indicando explícitamente que quieres usar Bash. El shebang es importante cuando ejecutas directamente el archivo con:

./script.sh

¿Qué es mejor: #!/bin/bash o #!/usr/bin/env bash?

Depende del caso. #!/bin/bash usa una ruta fija y es habitual en scripts de sistema. #!/usr/bin/env bash busca Bash en el PATH, lo que puede ser más portable en entornos de usuario o proyectos que se ejecutan en distintos sistemas.


Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *