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.shque ejecutar:
bash script.sho:
sh script.sho incluso:
source script.shAunque 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:
bashshpython3perlnodeu otro intérprete.
Por eso en muchos scripts aparece una primera línea especial:
#!/bin/bashA 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.shContenido:
#!/bin/bash
echo "Directorio actual: $(pwd)"
echo "Usuario actual: $(whoami)"
echo "Shell usado: $SHELL"Guardamos el archivo y comprobamos sus permisos:
ls -l script.shPuede que veas algo parecido a esto:
-rw-r--r-- 1 david david 95 ene 10 10:30 script.shLa 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.shPero 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 deniedPara solucionarlo:
chmod +x script.shAhora sí:
./script.shSalida esperada:
Directorio actual: /home/david
Usuario actual: david
Shell usado: /bin/bashQué significa ./script.sh
El punto representa el directorio actual:
.La barra indica que queremos acceder a algo dentro de ese directorio:
/Por tanto:
./script.shsignifica:
Ejecuta el archivo
script.shque 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.shaunque el archivo exista.
En cambio, esto sí apunta directamente al archivo:
./script.shQué ocurre internamente al ejecutar ./script.sh
Cuando ejecutas:
./script.shLinux hace varias comprobaciones:
- Comprueba que el archivo existe.
- Comprueba que tienes permiso de ejecución.
- Lee la primera línea del archivo.
- Si encuentra un shebang, usa ese intérprete.
- Ejecuta el script en un nuevo proceso.
Si el archivo empieza así:
#!/bin/bashLinux usará:
/bin/bashpara interpretar el archivo.
Es decir, esto:
./script.shacaba siendo conceptualmente parecido a esto:
/bin/bash ./script.shPero 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.shEn 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.shporque 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.shLinux mira el shebang:
#!/bin/bashCon:
bash script.shel shebang pierde importancia, porque ya has elegido tú el intérprete.
Por ejemplo, imagina este script:
#!/bin/sh
echo "Hola"Si ejecutas:
./script.shse usará:
/bin/shPero si ejecutas:
bash script.shse 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.shPero 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/shEn algunas distribuciones verás algo parecido a:
/bin/sh -> dashEso significa que cuando ejecutas:
sh script.shno 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.shpuede funcionar:
Hola, DAVIDPero si ejecutas:
sh script.shpuede 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.shsolo 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.sho directamente con:
./script.shusando este shebang:
#!/bin/bashForma 4: ejecutar con source script.sh
La cuarta forma es diferente:
source script.shTambién se puede escribir como:
. script.shEn 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.shContenido:
#!/bin/bash
MI_VARIABLE="Hola desde el script"Ahora ejecútalo así:
bash variables.shDespué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.shY luego:
echo "$MI_VARIABLE"Ahora sí verás:
Hola desde el scriptPorque 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 ~/.bashrcsource .venv/bin/activatesource config.envTambién se usa para cargar variables:
source variables.sho funciones:
source funciones.shPero no deberías usar source para ejecutar cualquier script sin pensar.
Si el script contiene:
cd /tmpy lo ejecutas con:
source script.shtu terminal cambiará realmente al directorio /tmp.
En cambio, si lo ejecutas con:
bash script.shel cambio de directorio solo ocurre dentro del proceso del script.
Comparativa rápida
| Comando | Usa shebang | Necesita chmod +x | Ejecuta en nueva shell | Afecta la shell actual |
|---|---|---|---|---|
./script.sh | Sí | Sí | Sí | No |
bash script.sh | No realmente | No | Sí | No |
sh script.sh | No realmente | No | Sí | No |
source script.sh | No | No | No | Sí |
Diferencia entre ejecutar y leer un script
Esto es importante:
./script.shejecuta directamente el archivo.
Pero esto:
bash script.shejecuta 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.shAhora esto fallará:
./script.shPero esto puede seguir funcionando:
bash script.shPorque 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/bashSirve para indicar qué intérprete debe usarse cuando el archivo se ejecuta directamente.
Por ejemplo:
#!/bin/bashusa Bash.
#!/bin/shusa sh.
#!/usr/bin/env bashbusca bash en el PATH.
#!/usr/bin/env python3busca python3 en el PATH.
El shebang solo es realmente importante cuando ejecutas el archivo directamente:
./script.shNo cuando haces:
bash script.shporque 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/bashy:
#!/usr/bin/env bashLa primera usa una ruta fija.
La segunda busca Bash usando el entorno actual.
En sistemas Linux tradicionales, Bash suele estar en:
/bin/bashPero en otros entornos puede estar en otra ubicación.
Por ejemplo:
/usr/local/bin/bashCon:
#!/usr/bin/env bashel 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 bashArtí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.shnecesitas permiso de ejecución.
Se añade así:
chmod +x script.shDespués puedes comprobarlo con:
ls -l script.shAntes:
-rw-r--r--Después:
-rwxr-xr-xLa x indica permiso de ejecución.
También puedes asignar permisos de forma más explícita:
chmod 755 script.shEsto 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 deniedCausa probable:
El archivo no tiene permiso de ejecución.
Solución:
chmod +x script.sh
./script.shTambién puedes ejecutarlo sin cambiar permisos:
bash script.sh2. bad interpreter: No such file or directory
Error típico:
bad interpreter: No such file or directoryPuede tener varias causas.
Una de las más comunes es que el shebang apunta a un intérprete que no existe:
#!/bin/bashComprueba si existe:
ls -l /bin/bashOtra 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 interpreterEse ^M indica que el archivo tiene saltos de línea CRLF.
Solución:
dos2unix script.shO con sed:
sed -i 's/\r$//' script.sh3. command not found
Error:
script.sh: command not foundEsto puede pasar si intentas ejecutar:
script.shsin indicar la ruta.
Solución:
./script.shO mueve el script a un directorio incluido en el PATH, por ejemplo:
/usr/local/binTambién puedes crear un directorio personal para scripts:
mkdir -p ~/binY añadirlo al PATH en ~/.bashrc:
export PATH="$HOME/bin:$PATH"Después:
source ~/.bashrc4. Bad substitution
Error:
Bad substitutionSuele aparecer cuando ejecutas con sh un script que usa sintaxis de Bash.
Por ejemplo:
${variable^^}Solución:
Ejecuta con Bash:
bash script.sho usa shebang de Bash:
#!/bin/bashy luego:
chmod +x script.sh
./script.shEjemplo práctico completo
Vamos a crear un script algo más realista.
Archivo:
nano backup.shContenido:
#!/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.shEjecutamos:
./backup.shEste script:
- Define un directorio de origen.
- Define un directorio de destino.
- Crea la carpeta de backups si no existe.
- Genera un nombre de archivo con fecha.
- Comprime el directorio.
- Muestra un mensaje final.
Qué pasaría si usamos bash backup.sh
También funcionaría:
bash backup.shPero 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/bashlo correcto es ejecutarlo como script Bash:
./backup.sho:
bash backup.shQué 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/basho:
#!/usr/bin/env bashPara Python:
#!/usr/bin/env python3Activa errores estrictos cuando tenga sentido
En scripts Bash más serios, puedes usar:
set -euo pipefailEsto ayuda a detectar errores antes.
Significa:
set -eEl script se detiene si un comando falla.
set -uEl script falla si usas variables no definidas.
set -o pipefailEl 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 $archivoLas 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.
$0representa el nombre del script.
$1representa 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 0Esto 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.shEs 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.shTambié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.shNo 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 .envsource ~/.bashrcsource .venv/bin/activateNo 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.pypuedes darle permisos:
chmod +x script.pyy ejecutarlo:
./script.pyLinux leerá el shebang:
#!/usr/bin/env python3y usará Python 3 para ejecutar el archivo.
También podrías ejecutarlo así:
python3 script.pyEn 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.shEjecuta el archivo directamente, usa el shebang y requiere permisos de ejecución.
bash script.shEjecuta Bash y le pasa el archivo como entrada. No requiere chmod +x.
sh script.shEjecuta el script con sh, que puede no ser Bash. Puede fallar si el script usa sintaxis específica de Bash.
source script.shEjecuta 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.shTambién puedes ejecutarlo con:
bash script.shsi 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.


