En esta página
Terminal y Bash: de cero a un script
Todo lo que sigue se hace escribiendo, no con el mouse. Si nunca abriste una terminal, empieza por aquí: al final vas a poder compilar, moverte por carpetas y escribir un script que compile el Rush 00 por tú.
Qué es una terminal (y qué es un shell)
Son dos cosas distintas que se usan juntas:
| Pieza | Qué es | Ejemplo |
|---|---|---|
| Terminal | la ventana que muestra texto | GNOME Terminal, iTerm2, Windows Terminal |
| Shell | el programa que interpreta lo que escribes | bash, zsh, fish |
La terminal es el vidrio; el shell es el que trabaja. Cuando ves algo así:
laura@maquina:~/42-piscina$
Eso es el prompt. Se lee: usuario laura, máquina maquina, carpeta
actual ~/42-piscina, y $ significa "esperando una orden".
#en lugar de$significa que eres root (administrador). Si ves#y no querías estar ahí, sal antes de escribir cualquier cosa.
Cómo se lee un comando
ls -la ex00
| Parte | Nombre | Significado |
|---|---|---|
ls | comando | el programa que se ejecuta |
-la | opciones (flags) | modifican su comportamiento |
ex00 | argumento | sobre qué actúa |
Los flags cortos se pueden juntar: -l -a es lo mismo que -la. Los flags
largos usan dos guiones: --all.
Casi todos los comandos traen su manual:
man ls # manual completo (se sale con q)
ls --help # resumen corto
Atajos que te salvan la vida
| Atajo | Qué hace |
|---|---|
Tab | autocompleta nombres de archivos y comandos |
Ctrl+C | cancela el comando que está corriendo |
Ctrl+L | limpia la pantalla (como clear) |
Ctrl+R | busca en el historial de comandos |
↑ / ↓ | recorre comandos anteriores |
Ctrl+A / Ctrl+E | va al principio / final de la línea |
Ctrl+U | borra desde el cursor hasta el principio |
Tab es el atajo más importante: úsalo siempre y deja de escribir rutas a mano.
Rutas: dónde estás parado
Hay dos formas de nombrar una ubicación:
| Tipo | Ejemplo | Significa |
|---|---|---|
| absoluta | /home/laura/42-piscina | desde la raíz del sistema |
| relativa | ex00 o ../README.md | desde donde estás ahora |
Símbolos que vas a ver todo el tiempo:
| Símbolo | Significado |
|---|---|
/ | la raíz del sistema |
~ | tu carpeta personal (/home/laura) |
. | la carpeta actual |
.. | la carpeta de arriba |
- | la carpeta anterior (cd - vuelve) |
pwd # ¿dónde estoy?
cd ex00 # entro a ex00
cd .. # vuelvo atrás
cd ~ # voy a mi carpeta personal
cd - # vuelvo a la anterior
Ver archivos y moverse
ls # lista
ls -l # lista con detalles
ls -la # incluye archivos ocultos (los que empiezan con .)
ls -lh # tamaños legibles (K, M, G)
tree # árbol de carpetas (puede no estar instalado)
Ver el contenido sin abrir un editor:
cat README.md # todo de una
less README.md # paginado: q para salir, / para buscar
head -20 README.md # primeras 20 líneas
tail -20 README.md # últimas 20
tail -f archivo.log # sigue el archivo en vivo (Ctrl+C para cortar)
wc -l README.md # cuenta líneas
file rush00 # qué tipo de archivo es
Crear, copiar, mover y borrar
| Comando | Qué hace | Cuidado |
|---|---|---|
touch notas.txt | crea un archivo vacío | — |
mkdir ex01 | crea una carpeta | — |
mkdir -p a/b/c | crea toda la ruta | — |
cp origen destino | copia | -r para carpetas |
mv origen destino | mueve o renombra | pisa sin preguntar |
rm archivo | borra | no hay papelera |
rm -r carpeta | borra carpeta y contenido | no hay papelera |
La regla del
rm: en la terminal no existe "deshacer". Antes de escribirrm -rf algo, escribepwdyls algo. Dos segundos de verificación evitan perder el día.rm -rf /orm -rf ~son las dos formas más rápidas de destruir una máquina.
Buscar
find . -name "*.c" # archivos .c desde aquí hacia abajo
find . -type d -name "ex*" # solo carpetas
grep -rn "rush" ex00/ # busca el texto en todos los archivos
grep -n "int" ex00/main.c # número de línea de cada coincidencia
grep es el que más vas a usar. -r recorre carpetas, -n muestra líneas,
-i ignora mayúsculas.
Permisos: por qué un script "no se ejecuta"
ls -l rush00
-rwxr-xr-x 1 laura laura 16352 nov 1 13:00 rush00
Ese -rwxr-xr-x se lee en cuatro bloques:
- rwx r-x r-x
│ │ │ │
│ │ │ └── otros: leer y ejecutar
│ │ └──────── grupo: leer y ejecutar
│ └────────────── dueño: leer, escribir y ejecutar
└─────────────────── tipo: - archivo, d carpeta, l enlace
| Letra | Permiso | En un archivo | En una carpeta |
|---|---|---|---|
r | read | leerlo | listar su contenido |
w | write | modificarlo | crear/borrar dentro |
x | execute | ejecutarlo | entrar (cd) |
Cambiar permisos:
chmod +x script.sh # agrega ejecución para todos
chmod 644 archivo.txt # rw-r--r-- (archivo normal)
chmod 755 script.sh # rwxr-xr-x (script ejecutable)
chmod 600 clave.txt # rw------- (solo el dueño)
Los números son la suma de r=4, w=2, x=1 por cada bloque (dueño, grupo,
otros). 755 = 7 (4+2+1) + 5 (4+1) + 5 (4+1).
Si
./script.shdicePermission denied, casi siempre es que faltachmod +x. No es que el script esté mal escrito.
Redirecciones y pipes: el superpoder
Todo programa tiene tres canales:
| Canal | Número | Para qué |
|---|---|---|
| entrada | 0 (stdin) | de dónde lee |
| salida | 1 (stdout) | a dónde escribe el resultado |
| errores | 2 (stderr) | a dónde escribe los errores |
Se pueden redirigir:
ls > lista.txt # guarda la salida (pisa el archivo)
ls >> lista.txt # agrega al final
wc -l < lista.txt # lee la entrada desde un archivo
gcc main.c 2> errores.txt # guarda solo los errores
gcc main.c > todo.txt 2>&1 # guarda salida y errores juntos
ls no-existe 2> /dev/null # tira los errores a la basura
Y se pueden conectar programas con | (pipe): la salida de uno entra como
entrada del siguiente.
ls -l | grep ".c" # solo las líneas que contienen .c
cat README.md | wc -l # cuenta líneas del README
history | grep gcc # busca en tu historial
ls -l | sort -k5 -n | tail # los 5 archivos más pesados
tee escribe en pantalla y en un archivo:
gcc main.c 2>&1 | tee compilacion.log
Procesos
ps aux # todos los procesos
top # monitor en vivo (q para salir)
htop # versión linda, si está instalada
kill 1234 # pide terminar el proceso 1234 (amable)
kill -9 1234 # lo mata sí o sí (último recurso)
Desde la terminal:
| Atajo | Qué hace |
|---|---|
Ctrl+C | termina el proceso en primer plano |
Ctrl+Z | lo suspende y te devuelve el prompt |
comando & | lo lanza en segundo plano |
jobs | lista los trabajos suspendidos |
fg | trae el último al frente |
bg | lo sigue en segundo plano |
Si un programa "no termina",
Ctrl+Ces lo primero que hay que probar. Si no responde, abre otra terminal y busca el proceso conps aux.
Variables de entorno
Una variable es una caja con nombre. En el shell se usa así:
NOMBRE="laura" # asignar (sin espacios alrededor del =)
echo "$NOMBRE" # leer
export NOMBRE # hacerla visible a los programas que lances
Ese detalle del = es el error número uno:
NOMBRE = "laura" # MAL: intenta ejecutar el comando "NOMBRE"
NOMBRE="laura" # BIEN
La variable más importante es PATH: la lista de carpetas donde el shell busca
los comandos.
echo "$PATH" # carpetas separadas por :
which gcc # ¿de dónde sale gcc?
export PATH="$PATH:$HOME/bin" # agrega tu carpeta de scripts
Las comillas también importan:
echo $NOMBRE # si está vacío, no imprime nada
echo "$NOMBRE" # siempre una sola palabra, aunque tenga espacios
Regla práctica: comilla siempre las variables ("$VAR"). Evita el 90 % de
los bugs de scripting.
Dónde guardar la configuración
| Archivo | Cuándo se carga |
|---|---|
~/.bashrc | cada terminal interactiva de bash |
~/.bash_profile | al iniciar sesión (bash) |
~/.zshrc | cada terminal interactiva de zsh |
~/.config/fish/config.fish | cada terminal de fish |
Ahí van los export, los alias y el prompt:
alias ll="ls -la"
alias g="git"
Después de editar el archivo, recargalo:
source ~/.bashrc # o ~/.zshrc
Scripts en Bash
Un script es un archivo de texto con comandos. La primera línea (el shebang) dice con qué programa ejecutarlo:
#!/usr/bin/env bash
/usr/bin/env bash busca bash en el PATH: es más portable que
#!/bin/bash, que asume que bash está en esa ruta exacta.
Para ejecutarlo:
chmod +x script.sh # una sola vez
./script.sh # ejecutar
También se puede ejecutar sin permiso de ejecución:
bash script.sh # no usa el shebang; lo corre con bash
El encabezado que evita desastres
#!/usr/bin/env bash
set -euo pipefail
| Flag | Qué hace |
|---|---|
-e | corta el script si un comando falla |
-u | error si usas una variable no definida |
-o pipefail | un pipe falla si falla cualquiera de sus partes |
Sin esto, un script sigue adelante después de un error y termina "bien" con resultados basura. Con esto, falla temprano y fuerte.
Argumentos
| Variable | Significado |
|---|---|
$0 | nombre del script |
$1, $2… | argumentos posicionales |
$# | cantidad de argumentos |
$@ | todos los argumentos |
$? | código de salida del último comando (0 = bien) |
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 2 ]]; then
echo "Uso: $0 ANCHO ALTO" >&2
exit 1
fi
echo "Rectángulo de $1 x $2"
>&2 manda el mensaje al canal de errores: así el aviso no se mezcla con la
salida normal del programa.
Condicionales
if [[ -f "ex00/main.c" ]]; then
echo "existe"
elif [[ -d "ex00" ]]; then
echo "existe la carpeta pero no el archivo"
else
echo "no existe"
fi
| Prueba | Verdadera si… |
|---|---|
[[ -f ruta ]] | es un archivo |
[[ -d ruta ]] | es una carpeta |
[[ -x ruta ]] | es ejecutable |
[[ -z "$var" ]] | la cadena está vacía |
[[ -n "$var" ]] | la cadena no está vacía |
[[ "$a" == "$b" ]] | son iguales |
[[ "$a" != "$b" ]] | son distintas |
[[ $n -eq 3 ]] | números iguales (-ne, -lt, -gt, -le, -ge) |
Dos corchetes [[ ]] son la versión moderna de [ ]: manejan mejor los
espacios y las comillas. En scripts de bash, usa [[ ]].
También existen los atajos && (si salió bien) y || (si falló):
gcc main.c -o prog && ./prog # compila y, solo si compiló, ejecuta
gcc main.c -o prog || echo "falló" # avisa si falló
Bucles
for archivo in main.c ft_putchar.c rush00.c; do
echo "Revisando $archivo"
done
contador=0
while [[ $contador -lt 3 ]]; do
echo "Vuelta $contador"
contador=$((contador + 1))
done
Recorrer líneas de un archivo (el patrón correcto):
while IFS= read -r linea; do
echo "→ $linea"
done < lista.txt
IFS= evita que se coman los espacios; -r evita que se interpreten las
barras invertidas. Sin las dos, los archivos con espacios se rompen.
Funciones
saludar() {
local nombre="$1"
echo "Hola, $nombre"
}
saludar "laura"
local hace que la variable viva solo dentro de la función. Es el equivalente
a no contaminar el resto del script.
Script completo: compilar el Rush 00
Guarda esto como compilar.sh en la raíz del repo:
#!/usr/bin/env bash
set -euo pipefail
readonly CARPETA="ex00"
readonly ARCHIVOS=("main.c" "ft_putchar.c" "rush00.c")
for archivo in "${ARCHIVOS[@]}"; do
if [[ ! -f "$CARPETA/$archivo" ]]; then
echo "Falta $CARPETA/$archivo" >&2
exit 1
fi
done
gcc -Wall -Wextra -Werror \
"$CARPETA/main.c" \
"$CARPETA/ft_putchar.c" \
"$CARPETA/rush00.c" \
-o rush00
echo "Compilado: ./rush00"
Se ejecuta así:
chmod +x compilar.sh
./compilar.sh
./rush00
Cosas para mirar en el script:
| Línea | Por qué está |
|---|---|
set -euo pipefail | si algo falla, se entera |
readonly | evita que se reasignen por accidente |
ARCHIVOS=(...) | un array: varios valores en una variable |
"${ARCHIVOS[@]}" | recorre el array respetando espacios |
[[ ! -f ... ]] | verifica antes de compilar |
>&2 + exit 1 | error claro y código de salida correcto |
\ al final de línea | continúa el comando en la línea siguiente |
Un script que termina con
exit 0implícito "dijo que salió bien". Si tu script detecta un problema, tiene que devolver un código distinto de cero. Así&&y los sistemas de CI pueden reaccionar.
Revisar scripts con ShellCheck
shellcheck es un linter de bash: te marca comillas faltantes, variables sin
usar, comparaciones mal escritas y decenas de trampas más.
shellcheck compilar.sh
Si no está instalado, buscalo en el gestor de paquetes de tu sistema. Es de las mejores inversiones de cinco minutos que existen.
Errores típicos de scripting
| Error | Por qué falla | Solución |
|---|---|---|
VAR = 1 | los espacios convierten la asignación en un comando | VAR=1 |
$VAR sin comillas | se rompe con espacios y globs | "$VAR" |
cd carpeta sin verificar | si falla, sigues operando en la carpeta equivocada | cd carpeta || exit 1 |
for f in $(ls) | se rompe con nombres con espacios | for f in * o find |
[ $x = y ] con x vacío | error de sintaxis | [[ "$x" == "y" ]] |
#!/bin/bash en otro sistema | bash puede estar en otra ruta | #!/usr/bin/env bash |
| CRLF en el shebang | el sistema busca bash\r | dos2unix script.sh |
rm -rf con variable vacía | borra desde la raíz | set -u y comillas |
script sin chmod +x | Permission denied | chmod +x |
Chuleta
| Necesito | Comando |
|---|---|
| saber dónde estoy | pwd |
| listar con detalles | ls -la |
| cambiar de carpeta | cd ruta |
| crear carpeta | mkdir -p ruta |
| ver un archivo | less archivo |
| buscar texto | grep -rn "texto" . |
| buscar archivos | find . -name "*.c" |
| copiar carpeta | cp -r origen destino |
| borrar con cuidado | rm -r carpeta |
| ver permisos | ls -l |
| hacer ejecutable | chmod +x archivo |
| guardar salida | comando > archivo |
| encadenar | comando1 | comando2 |
| ver procesos | ps aux |
| matar proceso | kill PID |
| buscar en historial | Ctrl+R |
| ver variable | echo "$PATH" |
| editar config | vim ~/.bashrc |
| recargar config | source ~/.bashrc |
Siguiente parada: Git y GitHub Flow.
Hecho con amor para Laura, por Bogdan.