Terminal & Bash
Curso para principiantes

Curso de Terminal y Bash

Aprende a dominar la línea de comandos desde cero. Un curso práctico y progresivo que te llevará desde los conceptos básicos hasta la automatización con scripts.

Este curso es parte de los módulos previos al curso de Ciencia de Datos en Salud de Hazla con Datos y es complementario al curso de configuración del entorno de desarrollo. No necesitas experiencia previa: si puedes usar un navegador web, puedes aprender la terminal.

~10 horas
9 módulos
Desde cero

El timer Pomodoro te ayuda a estudiar en bloques cortos de concentración (25 min) con descansos. Está demostrado que mejora el aprendizaje y reduce la fatiga mental.

⚙️

Requisito previo: Configuración del entorno

Antes de comenzar, necesitas tener una terminal funcionando. Este curso te guía paso a paso según tu sistema operativo (Windows con WSL, macOS o Linux).

Ir al curso de configuración →
01

Introducción

¿Qué es la terminal?

Cuando usas tu computador normalmente, haces clic en iconos, arrastras archivos y navegas por menús visuales. Eso se llama interfaz gráfica (o GUI). La terminal es una forma diferente de interactuar con tu computador: en lugar de hacer clic, escribes instrucciones en texto. Puede parecer intimidante al principio, pero una vez que le tomas el ritmo, muchas tareas se vuelven más rápidas y poderosas.

Piensa en la terminal como una conversación directa con tu computador. Tú escribes un comando, presionas Enter, y el computador te responde con el resultado. Así de simple.

¿Por qué es importante para ciencia de datos?

Este curso es parte de los módulos previos al curso de Ciencia de Datos en Salud de Hazla con Datos y está pensado como un complemento directo del curso de configuración del entorno de desarrollo. Si estás aprendiendo ciencia de datos, la terminal va a aparecer constantemente en tu camino:

  • Instalar herramientas: Python, R, librerías, gestores de paquetes… todo se instala más fácil por terminal.
  • Usar Git: El control de versiones, fundamental para cualquier proyecto de datos, funciona desde la terminal.
  • Trabajar con servidores: Si necesitas procesar datos en la nube o en un servidor remoto, la terminal es tu única opción.
  • Automatizar tareas: ¿Descargar datos todos los días? ¿Limpiar archivos temporales? Los scripts de Bash lo hacen por ti.
  • Docker y contenedores: Herramientas modernas de ciencia de datos se manejan desde la línea de comandos.

No necesitas ser experto en terminal para hacer ciencia de datos, pero sí necesitas sentirte cómodo con lo básico. Este curso te lleva exactamente hasta ese punto.

Conceptos clave que debes conocer

Antes de empezar, hay algunos términos que vas a escuchar mucho. No te preocupes por memorizarlos ahora; los irás entendiendo con la práctica.

La terminal es la aplicación o ventana donde escribes comandos. En Windows puedes usar Windows Terminal con WSL, en macOS está la app Terminal, y en Linux hay varias opciones como GNOME Terminal o Konsole.

El shell es el programa que interpreta lo que escribes y lo convierte en instrucciones que el computador entiende. Es como un traductor entre tú y el sistema operativo. Los shells más comunes son:

  • Bash (“Bourne Again Shell”): el shell estándar en la mayoría de distribuciones Linux. Es el que usaremos en este curso.
  • Zsh (“Z Shell”): un shell más moderno que viene por defecto en macOS desde Catalina. Tiene mejor autocompletado y personalización.

La buena noticia es que Bash y Zsh son muy similares para uso básico. Todo lo que aprenderás en este curso funciona igual en ambos. Las diferencias importantes solo aparecen en configuraciones avanzadas que no cubrimos aquí.

El prompt es el texto que aparece antes de tu cursor, esperando que escribas algo. Generalmente muestra tu nombre de usuario, el nombre del computador y el directorio donde estás. Se ve algo así:

Terminal window
usuario@mi-pc:~$

Cuando veas el $ al final, significa que la terminal está lista para recibir tu comando.

Configuración del entorno

⚙️

Requisito previo: Configuración del entorno

Antes de continuar, necesitas tener una terminal funcionando en tu computador. Si aún no la tienes lista, sigue el curso de configuración del entorno donde te guiamos paso a paso según tu sistema operativo (Windows con WSL, macOS o Linux).

Ir al curso de configuración →

Tu primer comando

Una vez que tengas tu terminal abierta, vamos a verificar que todo funciona. Escribe exactamente esto y presiona Enter:

Terminal window
echo "¡Hola, terminal!"

Si ves el mensaje ¡Hola, terminal! en la pantalla, felicidades: tu terminal está funcionando correctamente y acabas de ejecutar tu primer comando. El comando echo simplemente repite lo que le escribas. Parece básico, pero lo usarás mucho más adelante.

No te preocupes por los errores

Si escribes algo mal, la terminal te mostrará un mensaje de error. No pasa nada grave: simplemente lee el mensaje, corrige el comando y vuelve a intentar. La terminal no va a “romperse” porque te equivoques en un comando.

Ejercicios del módulo

Antes de pasar al siguiente módulo, practica lo siguiente:

  1. Abre tu terminal y escribe echo seguido de tu nombre. ¿Qué aparece?
  2. Escribe un comando cualquiera inventado (como hola). Lee el mensaje de error que aparece. ¿Qué te dice?
  3. Presiona la flecha arriba en tu teclado. ¿Qué pasa? Esto te será muy útil más adelante.
  4. Escribe date y presiona Enter. ¿Qué información te muestra?
02

Primeros pasos y navegación

Tus primeros comandos

Ahora que ya sabes abrir la terminal y ejecutar un comando, vamos a conocer algunos comandos básicos que te ayudarán a orientarte. Piensa en estos como las primeras palabras que aprendes en un idioma nuevo.

El comando echo ya lo conoces: repite lo que le escribas. Pero hay otros igual de sencillos:

Terminal window
echo "Hola mundo" # Imprime texto en pantalla
whoami # Muestra tu nombre de usuario
date # Muestra la fecha y hora actual
cal # Muestra el calendario del mes
clear # Limpia la pantalla (o Ctrl+L)

Prueba cada uno de estos comandos en tu terminal. No necesitas memorizarlos, solo familiarízate con la idea de que cada comando tiene un nombre corto y hace una tarea específica. Con el tiempo los irás recordando de forma natural.

Atajo útil

Puedes usar Ctrl + L para limpiar la pantalla rápidamente, en lugar de escribir clear. Este atajo funciona en casi todas las terminales y lo usarás todo el tiempo.

El sistema de archivos: cómo se organiza todo

Antes de aprender a moverte por el sistema, necesitas entender cómo está organizado. En tu computador, los archivos están guardados dentro de carpetas (también llamadas directorios), y esas carpetas pueden contener otras carpetas, formando una estructura como un árbol invertido.

En Linux y macOS, todo parte de un directorio raíz llamado / (una barra diagonal). Desde ahí se ramifica todo lo demás:

/
├── home/ # Aquí viven los directorios de cada usuario
│ └── tu-usuario/
│ ├── Documentos/
│ ├── Descargas/
│ └── ...
├── etc/ # Archivos de configuración del sistema
├── var/ # Datos variables (logs, bases de datos)
├── tmp/ # Archivos temporales
└── usr/ # Programas instalados

Lo más importante para ti ahora es la carpeta home (representada por ~). Es tu espacio personal dentro del sistema. Cuando abres la terminal, normalmente empiezas ahí. Es como tu escritorio, pero en la terminal.

Saber dónde estás: pwd

Cuando navegas por carpetas en la interfaz gráfica, puedes ver en qué carpeta estás mirando la barra de direcciones. En la terminal, usas el comando pwd (que significa “print working directory”, o “imprime el directorio de trabajo”):

/home/tu-usuario
pwd

Este comando es tu brújula. Cada vez que te sientas perdido, escribe pwd y sabrás exactamente dónde estás.

Ver qué hay alrededor: ls

Una vez que sabes dónde estás, querrás ver qué archivos y carpetas hay en ese lugar. Para eso usas ls (de “list”):

Terminal window
# Ver qué hay en el directorio actual
ls
# Ver con más detalle (permisos, tamaño, fecha)
ls -l
# Incluir archivos ocultos (los que empiezan con un punto)
ls -la
# Tamaños en formato legible (KB, MB, GB en vez de bytes)
ls -lh

¿Qué son los archivos ocultos? En Linux, cualquier archivo o carpeta cuyo nombre empiece con un punto (.) está oculto por defecto. Estos suelen ser archivos de configuración. Por ejemplo, .bashrc es el archivo de configuración de Bash. El flag -a le dice a ls que los muestre también.

💡

¿Qué son los flags?

Los flags (o banderas) son opciones que modifican el comportamiento de un comando. Se escriben con un guión antes de una letra: -l, -a, -h. Puedes combinarlos: ls -la es lo mismo que ls -l -a. Cada comando tiene sus propios flags; no necesitas aprenderlos todos, solo los más útiles.

Moverse entre carpetas: cd

Para entrar a una carpeta, usas cd (de “change directory”). Para salir, usas cd .. (los dos puntos significan “el directorio de arriba”):

Comando Descripción
cd carpeta Entra a un directorio
cd .. Sube un nivel (al directorio padre)
cd ~ Ir al directorio home, sin importar dónde estés
cd - Volver al directorio donde estabas antes
cd / Ir al directorio raíz del sistema

Vamos a practicar la navegación paso a paso:

/home/tu-usuario
# Primero, veamos dónde estamos
pwd
# ¿Qué hay aquí?
ls
# Documentos Descargas Escritorio Imágenes
# Entremos a Documentos
cd Documentos
# Verificamos que nos movimos
pwd
# /home/tu-usuario/Documentos
# Subimos un nivel (volvemos a home)
cd ..
# Verificamos
pwd
# /home/tu-usuario
# Vamos directo al home desde cualquier lugar
cd ~

Rutas absolutas vs relativas

Hay dos formas de decirle a la terminal a qué carpeta quieres ir. Entender la diferencia es importante porque la usarás en todo momento.

Una ruta absoluta empieza siempre desde la raíz /. Es como dar una dirección completa: “Chile, Santiago, calle X, número Y”. No importa dónde estés, la ruta absoluta siempre te lleva al mismo lugar:

Terminal window
cd /home/usuario/Documentos/proyecto

Una ruta relativa empieza desde donde tú estás ahora. Es como decir “la tienda de la esquina”: depende de dónde te encuentres en ese momento:

Terminal window
# Si estás en /home/usuario, esto te lleva a /home/usuario/Documentos/proyecto
cd Documentos/proyecto
# Los dos puntos (..) significan "sube un nivel"
cd ../otro-proyecto

¿Cuándo usar cada una?

Usa rutas relativas para moverte entre carpetas cercanas (es más corto de escribir). Usa rutas absolutas cuando quieras ir a un lugar específico sin importar dónde estés, o dentro de scripts para evitar errores.

Símbolos especiales de ruta

Estos símbolos los usarás constantemente. Vale la pena entenderlos bien:

SímboloSignificadoEjemplo
.El directorio donde estás ahora./script.sh (ejecutar algo aquí)
..El directorio de arriba (padre)cd .. (subir un nivel)
~Tu directorio homecd ~ (ir a casa)
/La raíz del sistema (el punto más alto)cd /
-El directorio anterior (solo con cd)cd - (ir y volver)

Autocompletado con Tab: tu mejor herramienta

Si hay un truco que debes aprender de este curso, es este: la tecla Tab autocompleta nombres. No necesitas escribir nombres completos de archivos o carpetas. Escribe las primeras letras y presiona Tab; la terminal completa el resto por ti.

Terminal window
# Escribe "cd Doc" y presiona Tab
cd Doc⇥ # Se completa a: cd Documentos/
# Si hay varias opciones que empiezan igual, presiona Tab dos veces
# y la terminal te muestra todas las posibilidades
cd D⇥⇥
# Descargas/ Documentos/ Desktop/

Esto no solo te ahorra tiempo: evita errores de escritura. Si Tab no completa nada, probablemente el archivo o carpeta no existe, o escribiste mal las primeras letras.

Usa Tab obsesivamente

Los usuarios experimentados de terminal presionan Tab después de cada 2-3 letras. Es un hábito que deberías adoptar desde ahora. Te ahorrará cientos de errores y mucho tiempo.

Historial de comandos

La terminal recuerda todos los comandos que has escrito. Esto es increíblemente útil porque rara vez necesitas escribir un comando desde cero:

  • Flecha arriba: Muestra el comando anterior. Sigue presionando para ir más atrás.
  • Flecha abajo: Vuelve hacia comandos más recientes.
  • history: Muestra el historial completo de comandos.
  • Ctrl + R: Busca un comando en el historial. Escribes parte del comando y te encuentra la coincidencia.
  • !!: Repite exactamente el último comando.
Terminal window
# Ver los últimos 10 comandos que ejecutaste
history | tail -10
# Buscar un comando que usaste antes
# Presiona Ctrl+R, escribe parte del comando (ej: "git") y aparecerá
💡

Ctrl+R es mágico

Imagina que hace una hora escribiste un comando largo y complicado. En lugar de recordarlo letra por letra, presionas Ctrl + R, escribes unas pocas letras que recuerdas, y la terminal lo encuentra por ti. Es uno de los atajos más útiles que existen.

Ejercicios del módulo

Practica cada uno de estos ejercicios en tu terminal:

  1. Ejecuta whoami, date y cal uno por uno. ¿Qué te muestra cada uno?
  2. Usa pwd para ver dónde estás. Luego usa ls para ver qué hay en tu directorio home.
  3. Usa ls -la y compara con ls. ¿Qué archivos nuevos aparecen? (Pista: busca los que empiezan con punto)
  4. Navega a una carpeta cualquiera con cd, luego usa pwd para confirmar dónde estás. Vuelve al home con cd ~.
  5. Practica el autocompletado: escribe cd seguido de las primeras 2 letras de una carpeta y presiona Tab. ¿Se completó?
  6. Ejecuta history y mira los comandos que has escrito en esta sesión. Luego presiona Ctrl + R y busca el comando date.
  7. Navega a /tmp con ruta absoluta, luego vuelve a tu home con cd ~. Ahora usa cd -. ¿A dónde te lleva?
03

Archivos y directorios

Ahora que sabes moverte por el sistema de archivos, es momento de aprender a crear, copiar, mover y eliminar archivos y carpetas. Estos son los comandos que más usarás en el día a día.

Crear directorios con mkdir

El comando mkdir (de “make directory”) crea una carpeta nueva. Es equivalente a hacer clic derecho y seleccionar “Nueva carpeta” en la interfaz gráfica, pero más rápido:

Terminal window
# Crear una carpeta
mkdir mi-proyecto
# Crear varias carpetas a la vez
mkdir css js img

¿Y si necesitas crear una carpeta dentro de otra que tampoco existe? Por ejemplo, quieres crear proyecto/src/components pero ni proyecto ni src existen todavía. Si intentas hacerlo directamente, obtendrás un error. Para eso existe el flag -p, que crea toda la estructura de carpetas intermedias:

Terminal window
# Sin -p, esto daría error si "proyecto" no existe
mkdir -p proyecto/src/components
# Crea "proyecto", luego "src" dentro, luego "components" dentro

Consejo práctico

Acostúmbrate a usar mkdir -p siempre. Si las carpetas ya existen, no pasa nada (no da error). Si no existen, las crea. Es más seguro.

Crear archivos con touch

El comando touch crea un archivo vacío. Su nombre viene de “tocar” el archivo; si el archivo ya existe, simplemente actualiza su fecha de modificación sin cambiar el contenido:

Terminal window
# Crear un archivo vacío
touch archivo.txt
# Crear varios archivos de una vez
touch index.html style.css app.js
# Si el archivo ya existe, solo actualiza la fecha (no borra nada)
touch archivo-existente.txt

En la práctica, touch es la forma más rápida de crear un archivo vacío que luego vas a editar.

Copiar archivos y directorios con cp

El comando cp (de “copy”) copia archivos. Funciona con la lógica de cp origen destino:

Terminal window
# Copiar un archivo
cp archivo.txt copia.txt
# Copiar un archivo a otra carpeta
cp archivo.txt carpeta/
# Copiar un archivo a otra carpeta con otro nombre
cp archivo.txt carpeta/nuevo-nombre.txt

Para copiar una carpeta completa con todo su contenido, necesitas el flag -r (de “recursivo”). Sin este flag, cp solo copia archivos sueltos:

Terminal window
# Esto NO funciona sin -r (da error)
cp mi-carpeta/ copia-carpeta/
# Esto SÍ funciona: copia la carpeta y todo lo de dentro
cp -r mi-carpeta/ copia-carpeta/
💡

¿Qué significa recursivo?

“Recursivo” significa que el comando se aplica a la carpeta y a todo lo que hay dentro: subcarpetas, archivos dentro de subcarpetas, etc. Verás el flag -r en varios comandos. Siempre significa lo mismo: “incluye todo lo de adentro”.

Un ejemplo práctico muy común es hacer un respaldo antes de modificar algo:

Terminal window
# Antes de hacer cambios importantes, haz una copia
cp -r mi-proyecto/ mi-proyecto-respaldo/

Mover y renombrar con mv

El comando mv (de “move”) hace dos cosas: mover archivos a otra ubicación y renombrar archivos. En la terminal, mover y renombrar son la misma operación:

Terminal window
# Renombrar un archivo (misma carpeta, otro nombre)
mv nombre-viejo.txt nombre-nuevo.txt
# Mover un archivo a otra carpeta (no cambia el nombre)
mv archivo.txt carpeta/
# Mover Y renombrar al mismo tiempo
mv viejo.txt carpeta/nuevo.txt
# Mover una carpeta completa (no necesita -r como cp)
mv proyecto/ /home/usuario/Documentos/

A diferencia de cp, el comando mv no necesita -r para mover carpetas. Simplemente las mueve completas.

mv no hace copia

Recuerda que mv mueve el archivo: desaparece del lugar original. Si quieres mantener el original y crear una copia en otro lugar, usa cp en su lugar.

Eliminar archivos y directorios con rm

Aquí necesitamos ir con mucho cuidado. El comando rm (de “remove”) elimina archivos permanentemente. No hay papelera de reciclaje, no hay “deshacer”, no hay manera de recuperar lo que borres. Una vez que presionas Enter, el archivo desaparece para siempre.

⚠️

rm es permanente e irreversible

A diferencia de la papelera de reciclaje de tu escritorio, rm elimina archivos de forma definitiva. Antes de ejecutar cualquier rm, lee dos veces lo que vas a borrar. Una buena práctica es usar ls primero con el mismo patrón para verificar qué archivos coinciden.

Terminal window
# Eliminar un archivo
rm archivo.txt
# Eliminar con confirmación (te pregunta antes de borrar cada archivo)
rm -i archivo.txt
# rm: ¿borrar el fichero regular 'archivo.txt'? (s/n)

Para eliminar carpetas, necesitas decidir si están vacías o no:

Terminal window
# Eliminar una carpeta vacía (solo funciona si no tiene nada dentro)
rmdir carpeta-vacia
# Eliminar una carpeta CON contenido (recursivo)
rm -r carpeta/
⚠️

PELIGRO: comandos que nunca debes ejecutar

Existen combinaciones de rm que pueden destruir tu sistema completo. Nunca ejecutes estos comandos:

  • rm -rf / — Borra TODO el sistema operativo.
  • rm -rf * — Borra todo el contenido del directorio actual.
  • rm -rf ~ — Borra todo tu directorio home (tus documentos, configuraciones, todo).

El flag -f (force) omite confirmaciones y el flag -r (recursive) borra todo lo de adentro. Juntos son extremadamente peligrosos si se aplican al lugar equivocado.

Una forma más segura de trabajar con rm es usar siempre el flag -i para que te pida confirmación, o verificar antes con ls:

Terminal window
# Primero verifica qué archivos vas a borrar
ls *.tmp
# archivo1.tmp archivo2.tmp resultado.tmp
# Si estás seguro, borra
rm *.tmp
# O usa -i para que te pregunte uno por uno
rm -i *.tmp

Wildcards (comodines): seleccionar varios archivos a la vez

Los comodines son patrones que te permiten referirte a múltiples archivos sin escribir cada nombre. Son muy útiles combinados con cp, mv, rm y ls:

El comodín más usado es * (asterisco), que significa “cualquier cantidad de cualquier carácter”:

Terminal window
# Todos los archivos que terminan en .txt
ls *.txt
# Todos los archivos que empiezan con "datos"
ls datos*
# Todos los archivos (cualquier nombre, cualquier extensión)
ls *

Otros comodines útiles:

WildcardSignificadoEjemplo
*Cualquier cantidad de caracteres*.txt = todos los .txt
?Exactamente un carácterarchivo?.txt = archivo1.txt, archivoA.txt
[abc]Uno de los caracteres listadosarchivo[123].txt = archivo1, archivo2, archivo3
[a-z]Un carácter en el rango[A-Z]*.txt = archivos que empiezan con mayúscula
Terminal window
# Copiar todas las imágenes a una carpeta
cp *.jpg imagenes/
cp *.png imagenes/
# Mover todos los archivos de datos
mv datos_*.csv carpeta-datos/
# Listar archivos que empiezan con "test"
ls test*
⚠️

Cuidado con rm y wildcards

Antes de ejecutar rm *.algo, siempre ejecuta ls *.algo primero para ver qué archivos coinciden. Un wildcard mal escrito puede borrar archivos que no esperabas. Por ejemplo, rm * .txt (con un espacio antes del punto) borraría TODOS los archivos y luego intentaría borrar un archivo llamado .txt.

Visualizar la estructura con tree

El comando tree te muestra la estructura de carpetas de forma visual, como un árbol. Es excelente para entender cómo está organizado un proyecto:

Terminal window
# Instalar tree (no viene preinstalado)
sudo apt install tree # Debian/Ubuntu/WSL
brew install tree # macOS
# Ver la estructura completa
tree
# Limitar la profundidad (2 niveles)
tree -L 2
# Ver solo directorios (sin archivos)
tree -d
Ejemplo de salida de tree
.
├── src/
├── index.html
├── css/
└── style.css
└── js/
└── app.js
├── package.json
└── README.md

Encontrar archivos con find

Cuando tienes muchos archivos y carpetas, find te ayuda a buscar archivos por nombre, tipo, tamaño o fecha de modificación:

Terminal window
# Buscar todos los archivos .txt desde el directorio actual
find . -name "*.txt"
# Buscar solo directorios con un nombre específico
find . -type d -name "src"
# Buscar archivos modificados en las últimas 24 horas
find . -mtime -1
# Buscar archivos mayores a 10MB
find . -size +10M

El punto . al inicio significa “buscar desde aquí”. Podrías reemplazarlo por cualquier ruta, como /home/usuario o /var/log.

Resumen de comandos

Comando Descripción
mkdir carpeta Crear directorio
mkdir -p a/b/c Crear directorios anidados
touch archivo Crear archivo vacío
cp origen destino Copiar archivo
cp -r carpeta/ copia/ Copiar directorio completo
mv origen destino Mover o renombrar
rm archivo Eliminar archivo (permanente)
rm -i archivo Eliminar con confirmación
rm -r carpeta/ Eliminar directorio y todo su contenido
rmdir carpeta Eliminar directorio vacío
tree Ver estructura de directorios visualmente
find . -name patrón Buscar archivos por nombre

Ejercicios del módulo

  1. Crea una carpeta llamada practica en tu home. Dentro de ella, crea tres subcarpetas: datos, scripts y resultados.
  2. Usando un solo comando con mkdir -p, crea la estructura proyecto/src/utils.
  3. Dentro de practica, crea 3 archivos vacíos: nota1.txt, nota2.txt y nota3.txt.
  4. Copia nota1.txt a datos/ con el nombre copia-nota.txt.
  5. Renombra nota3.txt a nota-final.txt usando mv.
  6. Usa ls *.txt dentro de practica para ver todos los archivos .txt. ¿Cuántos aparecen?
  7. Elimina nota2.txt usando rm -i (con confirmación). Responde “s” cuando te pregunte.
  8. Usa tree practica para ver la estructura completa que creaste. ¿Se ve como esperabas?
  9. Usa find practica -name "*.txt" para encontrar todos los .txt dentro de la carpeta. ¿Encuentra también el que copiaste a datos/?
  10. Desafío: Elimina toda la carpeta practica con un solo comando. (Pista: necesitarás -r)
04

Visualización, búsqueda y redirecciones

En el módulo anterior aprendiste a crear y mover archivos. Ahora vas a aprender a ver lo que hay dentro de esos archivos, a buscar texto específico y a conectar comandos entre sí. Estas habilidades son las que realmente hacen poderosa a la terminal.

Ver el contenido de un archivo: cat

El comando más simple para ver el contenido de un archivo es cat (de “concatenate”). Muestra todo el contenido de una vez en la pantalla:

Terminal window
cat notas.txt

cat funciona bien para archivos cortos. Pero si el archivo tiene cientos o miles de líneas, el texto pasará tan rápido que no podrás leerlo. Para esos casos, hay mejores opciones.

Cuando necesitas leer un archivo largo, less te permite navegar página por página, como un visor de documentos:

Terminal window
less archivo-largo.txt

Dentro de less, usas estas teclas para moverte:

TeclaAcción
EspacioAvanzar una página
bRetroceder una página
Flecha arriba/abajoMover línea por línea
/textoBuscar “texto” hacia adelante
nIr a la siguiente coincidencia de búsqueda
qSalir de less

less es tu visor de archivos

Piensa en less como el equivalente a abrir un archivo con un visor de texto. Es perfecto para archivos de configuración, logs, o cualquier archivo que no necesitas editar, solo leer. Cuando termines de leer, presiona q para salir.

Ver solo el inicio o el final: head y tail

A veces no necesitas ver todo el archivo, solo las primeras o las últimas líneas. Para eso existen head y tail:

Terminal window
# Ver las primeras 10 líneas (por defecto)
head archivo.txt
# Ver las primeras 20 líneas
head -n 20 datos.csv
# Ver las últimas 10 líneas
tail archivo.txt
# Ver las últimas 5 líneas
tail -n 5 log.txt

tail tiene un truco especialmente útil: el flag -f (de “follow”) te permite monitorear un archivo en tiempo real. Cada vez que se agrega una nueva línea al archivo, aparece automáticamente en tu pantalla. Esto es invaluable para monitorear logs:

Terminal window
# Monitorear un archivo de log en tiempo real
tail -f /var/log/syslog
# Presiona Ctrl+C para dejar de monitorear

Contar líneas, palabras y caracteres: wc

El comando wc (de “word count”) cuenta las líneas, palabras y caracteres de un archivo:

Terminal window
wc archivo.txt
# 42 318 1847 archivo.txt
# (42 líneas, 318 palabras, 1847 caracteres)
# Si solo te interesa la cantidad de líneas
wc -l archivo.txt
Comando Descripción
cat archivo Muestra todo el contenido del archivo
less archivo Visor paginado (navegar con flechas, salir con q)
head archivo Muestra las primeras 10 líneas
head -n 20 archivo Muestra las primeras 20 líneas
tail archivo Muestra las últimas 10 líneas
tail -f archivo Monitorea el archivo en tiempo real (Ctrl+C para salir)
wc archivo Cuenta líneas, palabras y caracteres
wc -l archivo Cuenta solo las líneas

Buscar texto dentro de archivos: grep

grep es uno de los comandos más útiles que vas a aprender. Te permite buscar una palabra o patrón de texto dentro de uno o varios archivos. Su nombre viene de “Global Regular Expression Print”, pero no te preocupes por eso: piensa en grep como “buscar texto”.

La sintaxis básica es grep "lo que buscas" dónde buscas:

Terminal window
# Buscar la palabra "error" en un archivo de log
grep "error" log.txt
# La terminal mostrará todas las líneas que contengan "error"

Ahora veamos las opciones más útiles de grep, una por una:

Terminal window
# Ignorar mayúsculas/minúsculas (-i)
# Encuentra "Error", "ERROR", "error", etc.
grep -i "error" log.txt
# Mostrar el número de línea donde aparece (-n)
grep -n "error" log.txt
# 23: [2024-01-15] error de conexión
# 47: [2024-01-15] error de timeout
# Buscar en todos los archivos de una carpeta, recursivamente (-r)
grep -r "TODO" ./src/
# Mostrar líneas que NO contienen el texto (-v)
# Útil para filtrar: "todo excepto las líneas de debug"
grep -v "debug" log.txt
# Contar cuántas veces aparece (-c)
grep -c "error" log.txt
# 15
# Solo mostrar los nombres de archivo que contienen el texto (-l)
grep -rl "password" ./config/
Comando Descripción
grep 'texto' archivo Buscar texto en un archivo
grep -i Buscar sin distinguir mayúsculas/minúsculas
grep -n Mostrar números de línea
grep -r Buscar en todos los archivos de una carpeta
grep -v Mostrar líneas que NO contienen el texto
grep -c Contar coincidencias
grep -l Solo mostrar nombres de archivos con coincidencias
💡

grep y ciencia de datos

Si trabajas con archivos CSV o datos tabulares, grep te permite filtrar filas rápidamente. Por ejemplo, grep "Chile" datos.csv te muestra solo las filas que mencionan a Chile. No reemplaza a pandas o R, pero para revisiones rápidas es muy práctico.

Pipes (tuberías): conectar comandos con |

Aquí es donde la terminal se vuelve realmente poderosa. El pipe (representado por el símbolo |) toma la salida de un comando y la pasa como entrada al siguiente. Piensa en él como una tubería que conecta la salida de una herramienta con la entrada de otra.

Imagina que tienes una lista de 1000 archivos y quieres encontrar solo los que contienen “datos”. Sin pipes, tendrías que guardar la lista en un archivo, luego buscar en ese archivo. Con pipes, lo haces en una sola línea:

Terminal window
# Sin pipes (engorroso)
ls > lista.txt
grep "datos" lista.txt
rm lista.txt
# Con pipes (una sola línea)
ls | grep "datos"

Algunos ejemplos prácticos que usarás frecuentemente:

Terminal window
# Listar archivos y filtrar por nombre
ls -la | grep ".txt"
# Contar cuántos archivos hay en el directorio
ls | wc -l
# Ver procesos y buscar uno específico
ps aux | grep "python"
# Ver el historial y buscar un comando
history | grep "git"
# Ordenar líneas de un archivo y eliminar duplicados
cat nombres.txt | sort | uniq

Fíjate cómo puedes encadenar varios pipes. Cada | pasa el resultado al siguiente comando. Es como una línea de ensamblaje: cada estación hace una tarea y pasa el resultado a la siguiente.

💡

La filosofía Unix

La terminal está diseñada con una idea simple: cada comando hace UNA cosa bien. Los pipes permiten combinar estos comandos pequeños para resolver problemas complejos. Es como tener piezas de LEGO: cada pieza es simple, pero juntas puedes construir lo que quieras.

Redirecciones: guardar la salida en archivos

Los pipes conectan comandos entre sí. Las redirecciones envían la salida de un comando a un archivo en vez de mostrarla en pantalla. Hay dos tipos principales:

> (mayor que) envía la salida a un archivo. Si el archivo existe, lo sobreescribe (borra lo anterior):

Terminal window
# Guardar el listado de archivos en un archivo
ls -la > listado.txt
# Guardar la fecha actual
date > fecha.txt
⚠️

Cuidado con >

El operador > sobreescribe el archivo sin preguntar. Si ya tenías contenido importante en ese archivo, se perderá. Siempre verifica que no estés sobreescribiendo algo que necesitas.

>> (doble mayor que) agrega al final del archivo, sin borrar lo que ya tenía:

Terminal window
# Agregar una línea al final
echo "primera línea" > notas.txt
echo "segunda línea" >> notas.txt
echo "tercera línea" >> notas.txt
# Ahora notas.txt tiene las tres líneas
cat notas.txt

También puedes redirigir los mensajes de error por separado:

OperadorFunciónEjemplo
>Redirigir salida a archivo (sobreescribe)echo "hola" > saludo.txt
>>Redirigir salida a archivo (añade al final)echo "adiós" >> saludo.txt
2>Redirigir solo errores a archivocomando 2> errores.log
&>Redirigir todo (salida + errores) a archivocomando &> todo.log
2>/dev/nullDescartar errores (no mostrarlos)find / -name "*.conf" 2>/dev/null

El último ejemplo es muy útil: /dev/null es un “agujero negro” donde puedes enviar lo que no te interesa. Si un comando produce muchos mensajes de error que no necesitas ver, los rediriges a /dev/null:

Terminal window
# find muestra errores de "permiso denegado" en muchas carpetas
# Con 2>/dev/null solo vemos los resultados útiles
find / -name "*.conf" 2>/dev/null

Combinando todo: ejemplos del mundo real

Ahora que conoces pipes y redirecciones, veamos cómo se combinan para resolver problemas reales:

Terminal window
# Encontrar los 5 archivos más grandes del directorio
du -sh * | sort -rh | head -5
# Buscar errores recientes en un log y guardarlos
grep -i "error" /var/log/syslog | tail -20 > errores-recientes.txt
# Contar cuántas líneas tiene cada archivo .txt
wc -l *.txt
# Ver las 10 palabras más frecuentes en un archivo
cat texto.txt | tr ' ' '\n' | sort | uniq -c | sort -rn | head -10

No te preocupes si el último ejemplo parece complejo. El punto es que puedes construir soluciones paso a paso, agregando un pipe a la vez. Primero prueba el primer comando, luego agrega un pipe y el segundo, y así sucesivamente.

Ejercicios del módulo

  1. Crea un archivo con echo "Línea 1" > prueba.txt, luego agrega “Línea 2” y “Línea 3” usando >>. Verifica con cat prueba.txt.
  2. Usa head -n 1 prueba.txt y tail -n 1 prueba.txt. ¿Qué línea muestra cada uno?
  3. Usa wc -l prueba.txt para contar las líneas del archivo. ¿Coincide con lo que esperabas?
  4. Ejecuta ls /usr/bin | wc -l para contar cuántos programas hay instalados en tu sistema.
  5. Usa ls /usr/bin | grep "python" para ver si tienes Python instalado. ¿Aparece algo?
  6. Guarda el resultado de ls -la ~ en un archivo llamado mi-home.txt usando >. Luego abre el archivo con less mi-home.txt.
  7. Ejecuta history | grep "cd" para ver todos los comandos cd que has usado en esta sesión.
  8. Crea un archivo con varias líneas: echo -e "banana\nmanzana\nnaranja\nbanana\nmanzana" > frutas.txt. Luego usa sort frutas.txt | uniq para ver las frutas sin duplicados.
  9. Usa grep -c "banana" frutas.txt para contar cuántas veces aparece “banana”.
  10. Desafío: Usa cat frutas.txt | sort | uniq -c | sort -rn para ver cuál es la fruta más frecuente. ¿Qué hace cada parte del comando?
05

Editores de texto

Hasta ahora has aprendido a ver archivos con cat y less, pero ¿qué pasa cuando necesitas modificar un archivo directamente en la terminal? Para eso existen los editores de texto en terminal. Son esenciales cuando trabajas en servidores remotos (que no tienen interfaz gráfica) o cuando necesitas hacer una edición rápida sin abrir otro programa.

En este módulo aprenderás dos editores: Nano (fácil y amigable) y Vim (potente pero con curva de aprendizaje). Como principiante, te recomiendo empezar con Nano y aprender solo lo básico de Vim.

Nano: el editor amigable

Nano es el editor de texto más fácil de usar en la terminal. Si has usado un editor de texto gráfico como Notepad, Nano se sentirá familiar: escribes, borras, y usas atajos de teclado para guardar y salir.

Para abrir un archivo con Nano, simplemente escribe:

Terminal window
# Abrir un archivo existente
nano archivo.txt
# Si el archivo no existe, Nano lo crea al guardar
nano nuevo-archivo.txt
# Abrir con números de línea visibles (recomendado)
nano -l archivo.txt

Cuando Nano se abra, verás el contenido del archivo en la pantalla y una barra de atajos en la parte inferior. Puedes empezar a escribir inmediatamente, como en cualquier editor de texto normal.

Los atajos que debes conocer

Nano muestra sus atajos en la parte inferior de la pantalla. El símbolo ^ significa la tecla Ctrl y M- significa la tecla Alt. Estos son los más importantes:

Comando Descripción
Ctrl + O Guardar el archivo (te pide confirmar el nombre)
Ctrl + X Salir de Nano (si hay cambios sin guardar, te pregunta)
Ctrl + K Cortar la línea completa donde está el cursor
Ctrl + U Pegar la línea cortada
Ctrl + W Buscar texto dentro del archivo
Ctrl + \ Buscar y reemplazar texto
Ctrl + G Mostrar la ayuda completa
Ctrl + C Mostrar en qué línea y columna está el cursor
Alt + U Deshacer el último cambio
Alt + E Rehacer (volver a aplicar un cambio deshecho)

El flujo más común en Nano

El 90% de las veces harás lo mismo: abrir el archivo, hacer tus cambios, presionar Ctrl + O para guardar, presionar Enter para confirmar, y luego Ctrl + X para salir. Practica esta secuencia hasta que sea automática.

Ejemplo práctico: crear tu primer script

Vamos a crear un pequeño script usando Nano. Esto combina lo que aprendiste en módulos anteriores con la edición de archivos:

Terminal window
# Abre Nano para crear un nuevo archivo
nano mi-script.sh

Dentro de Nano, escribe exactamente esto:

mi-script.sh
#!/bin/bash
echo "¡Mi primer script!"
echo "Fecha: $(date)"
echo "Usuario: $(whoami)"
echo "Estoy en: $(pwd)"

Ahora guarda y sal:

  1. Presiona Ctrl + O (guardar)
  2. Presiona Enter (confirmar nombre del archivo)
  3. Presiona Ctrl + X (salir)

Finalmente, haz el script ejecutable y ejecútalo:

Terminal window
chmod +x mi-script.sh
./mi-script.sh

Deberías ver algo como:

¡Mi primer script!
Fecha: sáb 14 feb 2026 15:30:00
Usuario: tu-usuario
Estoy en: /home/tu-usuario

Vim: el editor potente

Vim es un editor completamente diferente a Nano. Es extremadamente potente y eficiente una vez que lo dominas, pero tiene una curva de aprendizaje pronunciada. La razón principal para conocerlo es que viene instalado en prácticamente todos los sistemas Linux, incluyendo servidores donde Nano podría no estar disponible.

💡

¿Necesito aprender Vim?

Para empezar, no. Nano es suficiente para la mayoría de las tareas. Pero es muy útil conocer los comandos básicos de Vim porque eventualmente te encontrarás en un servidor donde sea la única opción disponible. Aquí aprenderás solo lo esencial para no quedarte atrapado.

El concepto de modos

Lo que hace a Vim confuso al principio es que tiene modos. En Nano, puedes escribir apenas lo abres. En Vim, cuando lo abres estás en modo Normal, donde las teclas no escriben texto sino que ejecutan comandos. Para escribir, necesitas cambiar al modo Inserción.

ModoCómo entrarPara qué sirve
NormalPresiona EscNavegar por el archivo, copiar, pegar, eliminar líneas
InserciónPresiona iEscribir texto, como en un editor normal
ComandoEscribe : (desde modo Normal)Guardar, salir, buscar, configurar

El flujo básico: abrir, editar, guardar, salir

Aquí está la secuencia completa para editar un archivo con Vim. Sigue estos pasos exactamente:

Terminal window
# Paso 1: Abrir el archivo
vim archivo.txt
# Paso 2: Vim se abre en modo Normal (no puedes escribir todavía)
# Presiona la tecla i para entrar en modo Inserción
# Verás -- INSERT -- en la parte inferior de la pantalla
# Paso 3: Escribe lo que necesites (ahora sí puedes escribir)
# Paso 4: Cuando termines de escribir, presiona Esc
# para volver al modo Normal
# Paso 5: Escribe :wq y presiona Enter para guardar y salir
# :w = write (guardar), :q = quit (salir)
⚠️

¿Atrapado en Vim?

Es uno de los memes más famosos de la programación: “¿Cómo salgo de Vim?”. Si alguna vez te quedas atrapado, presiona Esc varias veces (para asegurarte de estar en modo Normal) y luego escribe :q! y presiona Enter. El signo de exclamación significa “salir sin guardar, no me importan los cambios”. Esto te sacará siempre.

Comandos esenciales de Vim

No necesitas memorizar todos estos ahora. Solo conócelos como referencia para cuando los necesites:

Comando Descripción
i Entrar en modo inserción (escribir antes del cursor)
a Entrar en modo inserción (escribir después del cursor)
Esc Volver al modo normal (dejar de escribir)
:w Guardar el archivo
:q Salir (solo si no hay cambios sin guardar)
:wq Guardar y salir
:q! Salir SIN guardar (forzar salida)
dd Eliminar la línea completa (en modo normal)
yy Copiar la línea completa
p Pegar debajo de la línea actual
u Deshacer el último cambio
/texto Buscar 'texto' hacia adelante
n Ir a la siguiente coincidencia
G Ir al final del archivo
gg Ir al inicio del archivo

¿Cuándo usar cada editor?

SituaciónRecomendación
Edición rápida de un archivo de configuraciónNano — abre, edita, guarda, listo
Servidor remoto donde nano no está instaladoVim — siempre disponible
Estás empezando a aprender terminalNano — sin curva de aprendizaje
Quieres máxima productividad a largo plazoVim — pero requiere semanas de práctica
Editar archivos de código de un proyectoUn editor gráfico (VS Code, etc.) — mejor experiencia

Consejo para ciencia de datos

En tu trabajo diario de ciencia de datos, probablemente usarás VS Code, RStudio o Jupyter. Los editores de terminal son para ediciones rápidas de configuración (como .bashrc, archivos .env, o config.yaml) y para trabajar en servidores. No intentes desarrollar proyectos completos en Nano o Vim si tienes acceso a un editor gráfico.

Ejercicios del módulo

  1. Abre Nano con nano prueba-nano.txt, escribe tres líneas de texto cualquiera, guarda con Ctrl + O + Enter, y sal con Ctrl + X. Verifica con cat prueba-nano.txt.
  2. Vuelve a abrir el archivo con nano prueba-nano.txt. Usa Ctrl + K para cortar una línea y Ctrl + U para pegarla en otro lugar. Guarda y sal.
  3. Abre Nano y usa Ctrl + W para buscar una palabra dentro del archivo. ¿La encuentra?
  4. Crea el script mi-script.sh que mostramos en el ejemplo práctico. Dale permisos de ejecución y ejecútalo.
  5. Modifica mi-script.sh con Nano para agregar una línea que diga echo "Directorio home: $HOME". Guarda y ejecuta de nuevo.
  6. Abre Vim con vim prueba-vim.txt. Presiona i, escribe “Hola desde Vim”, presiona Esc, escribe :wq y presiona Enter. Verifica con cat prueba-vim.txt.
  7. Abre el mismo archivo en Vim. Practica la “salida de emergencia”: presiona Esc varias veces y luego escribe :q! + Enter.
  8. Desafío: Crea un script con Nano que muestre la fecha, tu usuario, y cuántos archivos hay en el directorio actual (pista: usa ls | wc -l).
06

Permisos y administración

En Linux, cada archivo y cada carpeta tiene permisos que determinan quién puede hacer qué con ellos. Esto es una de las bases de la seguridad del sistema: gracias a los permisos, otros usuarios no pueden leer tus archivos privados, los programas no pueden modificar archivos del sistema sin autorización, y tú mismo estás protegido de borrar cosas importantes por accidente.

Si vienes de Windows o macOS, probablemente nunca te has preocupado por permisos. En Linux, entenderlos es fundamental, especialmente cuando trabajas con scripts, servidores o datos sensibles. Al principio puede parecer complicado, pero en la práctica usarás los mismos patrones una y otra vez. Vamos paso a paso.

Entender los permisos desde la terminal

Los tres tipos de permisos

Cada archivo o carpeta en Linux tiene tres permisos fundamentales. Es importante entender que significan cosas distintas dependiendo de si se aplican a un archivo o a una carpeta:

PermisoLetraEn un archivoEn una carpeta
LecturarPuedes ver el contenido (abrirlo, copiarlo)Puedes listar qué hay dentro (ls)
EscriturawPuedes modificar o sobreescribir el contenidoPuedes crear, renombrar o eliminar archivos dentro
EjecuciónxPuedes ejecutarlo como programa o scriptPuedes entrar a la carpeta con cd

Veamos esto con ejemplos concretos para que quede claro:

  • Un archivo con permiso r pero sin w: puedes leerlo, pero no editarlo. Imagina un documento de referencia que no quieres que nadie modifique.
  • Un script .sh sin permiso x: aunque tenga código válido, la terminal te dirá “Permiso denegado” al intentar ejecutarlo. Necesitas darle x para que funcione.
  • Una carpeta sin permiso x: no puedes ni entrar con cd ni acceder a los archivos de dentro, aunque tengas r para listarla. Es como tener la lista de contenido de una caja fuerte pero no la llave para abrirla.
  • Una carpeta con x pero sin r: puedes entrar si conoces el nombre exacto de lo que buscas, pero no puedes listar su contenido. Es como una habitación oscura donde solo encuentras algo si sabes exactamente dónde está.
💡

¿Por qué importa esto para ciencia de datos?

Cuando trabajas con datos, los permisos te ayudan a proteger información sensible (datos de pacientes, credenciales de bases de datos, API keys). Un archivo con permisos 600 significa que solo tú puedes leerlo. Esto no es opcional: muchas herramientas como SSH se niegan a funcionar si tus claves privadas tienen permisos demasiado abiertos.

Las tres categorías de usuarios

Los permisos se aplican a tres grupos de personas diferentes:

CategoríaLetra¿Quién es?Ejemplo
OwneruEl dueño del archivo (generalmente quien lo creó)Tú, cuando creas un script
GroupgUn grupo de usuarios al que pertenece el archivoTu equipo de trabajo
OthersoTodos los demás usuarios del sistemaCualquier otra persona con acceso al servidor

Esto significa que un archivo puede tener permisos distintos para cada categoría. Por ejemplo, tú (owner) puedes leer y editar un archivo, tu equipo (group) solo puede leerlo, y el resto (others) no puede ni verlo.

Identificar permisos con ls -l

Esta es la habilidad más práctica: saber leer los permisos de cualquier archivo o carpeta. Cuando ejecutas ls -l, la primera columna muestra los permisos. Puede parecer críptico al principio, pero tiene una estructura muy clara:

Terminal window
ls -l mi-script.sh
# -rwxr-xr-- 1 paulo users 256 ene 15 10:30 mi-script.sh

Desglosemos esa cadena -rwxr-xr-- carácter por carácter:

- rwx r-x r--
│ │ │ │
│ │ │ └── Others (otros): r-- = solo pueden leer
│ │ └────── Group (grupo): r-x = pueden leer y ejecutar
│ └────────── Owner (dueño): rwx = puede leer, escribir y ejecutar
└──────────── Tipo: - = archivo normal (d = directorio, l = enlace)

El primer carácter indica el tipo del elemento:

  • - = archivo normal
  • d = directorio (carpeta)
  • l = enlace simbólico (un atajo a otro archivo)

Los siguientes 9 caracteres se leen en grupos de tres, siempre en el mismo orden: r (lectura), w (escritura), x (ejecución). Si hay un guión - en lugar de una letra, ese permiso está desactivado.

Veamos varios ejemplos para entrenar el ojo:

Terminal window
ls -l
# drwxr-xr-x carpeta/ ← directorio: todos pueden entrar y listar
# -rw-r--r-- documento.txt ← archivo: todos leen, solo el dueño edita
# -rwxr-xr-x programa ← ejecutable por todos
# -rw------- clave-privada.pem ← archivo privado: SOLO el dueño accede
# drwx------ .ssh/ ← carpeta privada: solo el dueño puede entrar
# -rwxrwxrwx peligroso.sh ← ¡cualquiera puede modificar y ejecutar!

Practica leyendo permisos

Ejecuta ls -la en tu directorio home y trata de leer los permisos de cada archivo. Identifica cuáles son carpetas (d), cuáles son privados (solo rw para el dueño), y cuáles son ejecutables (tienen x). Con práctica, leerás la cadena de permisos de un vistazo.

Otros datos que muestra ls -l

Además de los permisos, ls -l muestra información útil en cada columna:

Terminal window
-rwxr-xr-- 1 paulo users 256 ene 15 10:30 mi-script.sh
└── Nombre del archivo
└── Fecha de última modificación
└── Tamaño en bytes
└── Grupo propietario
└── Dueño (owner)
└── Número de enlaces
└── Permisos

Esto es especialmente útil para verificar quién es el dueño de un archivo y cuándo fue modificado por última vez.

Modificar permisos con chmod

El comando chmod (de “change mode”) es el que usarás para cambiar los permisos de archivos y carpetas. Hay dos formas de usarlo: el modo simbólico (con letras, más intuitivo) y el modo octal (con números, más rápido). Ambos hacen lo mismo, solo cambia la forma de expresarlo.

⚠️

Cuidado al cambiar permisos

Cambiar permisos incorrectamente puede tener consecuencias serias:

  • Dar permisos excesivos (chmod 777) a archivos sensibles expone datos privados a todos los usuarios del sistema.
  • Quitar permisos de ejecución a archivos del sistema puede dejar programas inutilizables.
  • Cambiar permisos recursivamente (chmod -R) en la carpeta equivocada puede afectar cientos de archivos de golpe.
  • Nunca ejecutes chmod -R 777 / — esto elimina todas las protecciones del sistema operativo completo.

Regla de oro: da los permisos mínimos necesarios. Si solo tú necesitas leer un archivo, usa 600, no 644.

Modo simbólico (con letras)

El modo simbólico es el más fácil de entender porque usas letras que ya conoces. La sintaxis es:

chmod [quién][operación][permiso] archivo

Quién:

  • u = owner (dueño)
  • g = group (grupo)
  • o = others (otros)
  • a = all (todos, equivale a u, g y o juntos)

Operación:

  • + = agregar un permiso
  • - = quitar un permiso
  • = = establecer permisos exactos (reemplaza los anteriores)

Permiso:

  • r = lectura
  • w = escritura
  • x = ejecución

Veamos ejemplos prácticos:

Terminal window
# Dar permiso de ejecución al dueño
chmod u+x script.sh
# Antes: -rw-r--r-- → Después: -rwxr--r--
# Quitar permiso de escritura a otros
chmod o-w archivo.txt
# Antes: -rw-r--rw- → Después: -rw-r--r--
# Dar lectura y ejecución al grupo
chmod g+rx programa
# Antes: -rwx------ → Después: -rwxr-x---
# Dar permiso de ejecución a TODOS
chmod a+x script.sh
# Equivalente a: chmod u+x,g+x,o+x script.sh
# Establecer permisos EXACTOS para el dueño (reemplaza los anteriores)
chmod u=rw archivo.txt
# El dueño tendrá SOLO lectura y escritura, sin importar lo que tenía antes
# Quitar TODOS los permisos a otros
chmod o= secreto.txt
# Antes: -rw-r--r-- → Después: -rw-r-----
# Combinación: dar todo al dueño, solo lectura al resto
chmod u=rwx,g=r,o=r programa

El caso más común

La situación más frecuente es hacer un script ejecutable después de crearlo:

Terminal window
chmod +x mi-script.sh

Cuando no especificas quién (u/g/o), se aplica a todos. Este comando lo usarás constantemente al crear scripts de Bash.

Modo octal (con números)

El modo numérico es más rápido y es el estándar cuando necesitas establecer todos los permisos de una sola vez. Cada permiso tiene un valor numérico:

PermisoValor
Lectura (r)4
Escritura (w)2
Ejecución (x)1
Sin permiso0

Para calcular el número de cada categoría, sumas los valores de los permisos que quieres activar. Luego escribes tres dígitos: uno para el dueño, otro para el grupo y otro para otros.

Veamos un ejemplo paso a paso:

Queremos: rwxr-xr--
Owner: r + w + x = 4 + 2 + 1 = 7
Group: r + - + x = 4 + 0 + 1 = 5
Others: r + - + - = 4 + 0 + 0 = 4
Resultado: chmod 754 archivo

Otro ejemplo, esta vez queremos que solo el dueño pueda leer y escribir:

Queremos: rw-------
Owner: r + w + - = 4 + 2 + 0 = 6
Group: - + - + - = 0 + 0 + 0 = 0
Others: - + - + - = 0 + 0 + 0 = 0
Resultado: chmod 600 archivo

Esta es la tabla de combinaciones más útiles. No necesitas memorizar todas: con el tiempo las más comunes se vuelven automáticas:

NúmeroPermisosSignificado
7rwxTodos los permisos
6rw-Lectura y escritura
5r-xLectura y ejecución
4r--Solo lectura
0---Sin permisos

Y los permisos completos más comunes que usarás en la práctica:

Comando Descripción
chmod 755 script.sh rwxr-xr-x — Scripts y programas: todos ejecutan, solo el dueño edita
chmod 644 archivo.txt rw-r--r-- — Archivos normales: todos leen, solo el dueño edita
chmod 700 carpeta/ rwx------ — Carpeta privada: solo el dueño tiene acceso
chmod 600 clave.pem rw------- — Archivo sensible: solo el dueño lee y escribe
chmod 444 referencia.txt r--r--r-- — Solo lectura para todos (protección contra edición)
💡

¿Cuál modo usar?

Para acciones simples como “hacer ejecutable”, el modo simbólico es más fácil: chmod +x script.sh. Para establecer permisos exactos de una vez, el modo numérico es más preciso: chmod 755 script.sh. Con el tiempo usarás ambos según la situación.

Cambiar permisos en carpetas (modo recursivo)

Cuando cambias permisos de una carpeta, los archivos que están dentro no cambian automáticamente. Si quieres cambiar los permisos de una carpeta y todo lo que contiene, usas la opción -R (recursivo):

Terminal window
# Cambiar permisos de la carpeta Y todo lo de adentro
chmod -R 755 mi-proyecto/
# Hacer privada una carpeta y todo su contenido
chmod -R 700 datos-sensibles/
⚠️

Cuidado con chmod -R

El modo recursivo -R cambia permisos de todos los archivos y subcarpetas de golpe. Esto puede causar problemas:

  • Si aplicas 755 recursivamente, todos los archivos quedan como ejecutables (incluyendo .txt, .csv, etc.), lo cual no tiene sentido.
  • Si te equivocas de carpeta, puedes afectar archivos del sistema.

Para aplicar permisos diferentes a archivos y carpetas, usa find:

Terminal window
# Carpetas con 755 (se puede entrar y listar)
find mi-proyecto/ -type d -exec chmod 755 {} \;
# Archivos con 644 (se puede leer pero no ejecutar)
find mi-proyecto/ -type f -exec chmod 644 {} \;

La máscara de permisos: umask

Cuando creas un archivo nuevo, ¿qué permisos tiene por defecto? Eso lo controla el umask. La máscara define qué permisos se quitan automáticamente al crear archivos y carpetas nuevos.

Terminal window
# Ver tu máscara actual
umask
# Salida típica: 0022

El valor 0022 significa que a los archivos nuevos se les quita el permiso de escritura (2) para el grupo y para otros. En la práctica:

ElementoPermisos baseMenos umask 022Permisos reales
Archivos666 (rw-rw-rw-)- 022644 (rw-r—r—)
Carpetas777 (rwxrwxrwx)- 022755 (rwxr-xr-x)

Esto explica por qué cuando creas un archivo con touch te sale rw-r--r-- y cuando creas una carpeta con mkdir te sale rwxr-xr-x.

Puedes cambiar el umask

Si trabajas con datos sensibles y quieres que los archivos nuevos sean privados por defecto:

Terminal window
# Solo el dueño puede leer y escribir archivos nuevos
umask 077

Esto solo afecta la sesión actual. Para hacerlo permanente, agrégalo a tu archivo ~/.bashrc.

Las máscaras más comunes:

umaskArchivos nuevosCarpetas nuevasUso típico
022644 (rw-r—r—)755 (rwxr-xr-x)Valor por defecto en la mayoría de sistemas
077600 (rw-------)700 (rwx------)Máxima privacidad
002664 (rw-rw-r—)775 (rwxrwxr-x)Trabajo en equipo (grupo puede editar)

El superusuario: sudo

En Linux, hay tareas que solo puede hacer el administrador (también llamado root o superusuario): instalar programas, modificar archivos del sistema, gestionar servicios, cambiar permisos de archivos que no te pertenecen, etc.

El comando sudo (de “Super User DO”) te permite ejecutar un solo comando con privilegios de administrador:

Terminal window
# Actualizar la lista de paquetes disponibles
sudo apt update
# Instalar un programa
sudo apt install htop
# Editar un archivo de configuración del sistema
sudo nano /etc/hosts

Cuando usas sudo, el sistema te pedirá tu contraseña. Esto es una medida de seguridad para confirmar que realmente eres tú. La contraseña se “recuerda” por unos minutos, así que no te la pedirá de nuevo inmediatamente.

¿Cuándo necesitas sudo?

La regla general es simple: necesitas sudo cuando quieres hacer algo fuera de tu directorio home o que afecta al sistema:

Terminal window
# Esto NO necesita sudo (es tu archivo, en tu carpeta)
chmod 755 ~/mi-script.sh
nano ~/notas.txt
mkdir ~/proyectos
# Esto SÍ necesita sudo (archivos del sistema o de otros usuarios)
sudo chmod 644 /etc/configuracion.conf
sudo chown usuario:grupo /opt/datos/
sudo apt install python3
⚠️

sudo es poder y responsabilidad

Con sudo puedes hacer cualquier cosa en el sistema, incluyendo destruirlo completamente. Algunas reglas de supervivencia:

  • Nunca ejecutes sudo rm -rf / ni variantes como sudo rm -rf /* — borra todo el sistema operativo.
  • Nunca copies comandos con sudo de internet sin entender qué hacen primero. Un comando malicioso con sudo puede instalar software dañino o borrar tus datos.
  • Nunca uses sudo chmod -R 777 / — elimina todas las protecciones de seguridad del sistema completo.
  • Si un comando no funciona sin sudo, pregúntate por qué necesita permisos de administrador antes de agregarlo. Muchas veces el problema real es otro (ruta incorrecta, archivo inexistente, etc.).
  • Nunca trabajes permanentemente como root (sudo su). Usa sudo solo para comandos específicos.

Relación entre permisos y sudo

Aquí es donde todo se conecta. Los permisos definen qué puedes hacer como usuario normal. Cuando los permisos te bloquean, tienes dos opciones:

  1. Cambiar los permisos (si el archivo es tuyo): chmod +x mi-script.sh
  2. Usar sudo (si el archivo no es tuyo o es del sistema): sudo nano /etc/hosts
Terminal window
# Intentas editar un archivo del sistema
nano /etc/hostname
# Error: permiso denegado (no eres root)
# Opción correcta: usar sudo para ese comando específico
sudo nano /etc/hostname

Un truco útil: si olvidaste poner sudo al inicio de un comando y te dio error de permisos, puedes ejecutar sudo !! para repetir el último comando con sudo:

Terminal window
apt update
# Error: permiso denegado
sudo !!
# Equivale a: sudo apt update

Cambiar propietario con chown

El comando chown (de “change owner”) cambia quién es el dueño de un archivo o carpeta. Siempre necesitas sudo para usarlo (salvo que estés cediendo algo que ya es tuyo):

Terminal window
# Cambiar solo el dueño
sudo chown maria archivo.txt
# Cambiar dueño y grupo a la vez
sudo chown maria:equipo-datos archivo.txt
# Cambiar recursivamente (carpeta y todo lo de adentro)
sudo chown -R maria:equipo-datos proyecto/

¿Cuándo necesitas chown? Principalmente cuando:

  • Descargas archivos que quedaron con un dueño incorrecto
  • Configuras carpetas compartidas en un servidor
  • Mueves archivos entre usuarios
Terminal window
# Ver quién es el dueño actual
ls -l datos.csv
# -rw-r--r-- 1 root root 1024 ene 15 10:30 datos.csv
# ↑ ↑
# dueño grupo → ¡El dueño es root! No puedes editarlo
# Cambiarlo a tu usuario
sudo chown paulo:paulo datos.csv
# Ahora puedes editarlo sin sudo
nano datos.csv # ¡Funciona!

Resumen visual de comandos

Comando Descripción
ls -l Ver permisos, dueño, grupo y tamaño de archivos
ls -la Igual pero incluyendo archivos ocultos
chmod +x archivo Hacer un archivo ejecutable
chmod 755 archivo Permisos rwxr-xr-x (script/programa)
chmod 644 archivo Permisos rw-r--r-- (archivo normal)
chmod 600 archivo Permisos rw------- (archivo privado)
chmod -R 700 carpeta/ Permisos solo para el dueño, recursivamente
umask Ver la máscara de permisos por defecto
sudo comando Ejecutar un comando como administrador
sudo !! Repetir el último comando con sudo
sudo chown usuario archivo Cambiar el dueño de un archivo
sudo chown -R usuario:grupo carpeta/ Cambiar dueño y grupo recursivamente

Ejercicios del módulo

  1. Ejecuta ls -la en tu directorio home. Observa la columna de permisos. Identifica al menos un directorio (d), un archivo oculto (empieza con .), y un archivo con permisos restrictivos.
  2. Crea un archivo secreto.txt con echo "datos confidenciales" > secreto.txt. Verifica sus permisos con ls -l secreto.txt. ¿Qué permisos tiene por defecto?
  3. Quita todos los permisos a otros usuarios: chmod o-rwx secreto.txt. Verifica con ls -l. ¿Cómo cambió la cadena de permisos?
  4. Ahora ponle permisos 600 (solo dueño lee y escribe): chmod 600 secreto.txt. Verifica con ls -l. ¿Ves la diferencia con el paso anterior?
  5. Crea un script: echo '#!/bin/bash' > script-test.sh && echo 'echo "funciona"' >> script-test.sh. Intenta ejecutarlo con ./script-test.sh. ¿Qué error te da y por qué?
  6. Dale permisos de ejecución con chmod +x script-test.sh. Ahora ejecútalo de nuevo. ¿Funciona? Verifica con ls -l que la x apareció.
  7. Usa chmod 755 script-test.sh y verifica con ls -l. Luego usa chmod 700 script-test.sh. ¿Cuál es la diferencia entre ambos?
  8. Ejecuta umask para ver tu máscara actual. Luego crea un archivo con touch nuevo.txt y una carpeta con mkdir nueva-carpeta. Verifica los permisos de ambos con ls -l. ¿Coinciden con lo que el umask predice?
  9. Intenta editar /etc/hostname con nano /etc/hostname (sin sudo). ¿Qué pasa? Ahora intenta con sudo nano /etc/hostname (pero sal sin guardar con Ctrl + X y luego N).
  10. Ejecuta sudo whoami. ¿Qué usuario aparece? Compara con whoami sin sudo. Esto demuestra que sudo te convierte temporalmente en root.
  11. Desafío 1: Calcula el número octal para los permisos rwxr--r--. Crea un archivo y aplica esos permisos. Verifica con ls -l.
  12. Desafío 2: Crea una carpeta proyecto/ con tres archivos dentro. Usa find con -exec chmod para poner las carpetas en 755 y los archivos en 644. Verifica con ls -lR.
07

Gestión de procesos

¿Qué es un proceso?

Cada vez que ejecutas un comando o abres un programa, el sistema crea un proceso. Un proceso es simplemente un programa en ejecución. Tu navegador es un proceso, tu terminal es un proceso, e incluso cada comando que ejecutas crea un proceso temporalmente.

Cada proceso tiene un número identificador único llamado PID (Process ID). Este número es importante porque lo necesitarás si alguna vez necesitas detener un programa que se quedó colgado.

Ver los procesos activos: ps

El comando ps (de “process status”) te muestra los procesos en ejecución. Por sí solo muestra solo los procesos de tu terminal actual, pero con los flags aux muestra todos los procesos del sistema:

Terminal window
# Ver solo los procesos de tu terminal
ps
# Ver TODOS los procesos del sistema con detalle
ps aux

La salida de ps aux tiene mucha información. Veamos qué significa cada columna:

Salida de ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 169316 13092 ? Ss 10:00 0:02 /sbin/init
paulo 1234 2.5 1.2 987456 98765 ? Sl 10:05 1:30 node server.js
paulo 5678 0.0 0.0 12345 6789 pts/0 S 10:30 0:00 bash
ColumnaSignificado
USERQuién ejecutó el proceso
PIDEl número identificador del proceso
%CPUCuánto procesador está usando (porcentaje)
%MEMCuánta memoria está usando (porcentaje)
COMMANDEl comando o programa que se ejecutó

En la práctica, rara vez leerás toda la lista. Normalmente combinas ps con grep para buscar un proceso específico:

Terminal window
# ¿Está corriendo Python?
ps aux | grep "python"
# ¿Hay algún servidor Node.js activo?
ps aux | grep "node"

Monitor en tiempo real: top y htop

Mientras ps te muestra una foto instantánea, top te muestra los procesos en tiempo real, actualizándose cada pocos segundos. Es como el Administrador de Tareas de Windows o el Monitor de Actividad de macOS, pero en la terminal:

Terminal window
# Monitor básico (viene preinstalado en todos los sistemas)
top
# Para salir de top, presiona q

Sin embargo, top es difícil de leer. htop es una versión mejorada con colores, barras visuales y mejor navegación:

Terminal window
# Instalar htop
sudo apt install htop # Debian/Ubuntu/WSL
brew install htop # macOS
# Ejecutar htop
htop

htop es mucho mejor que top

Si puedes instalar htop, hazlo. Muestra el uso de CPU y memoria con barras de colores, permite ordenar por columna con un clic, y puedes matar procesos directamente desde la interfaz. Presiona q para salir, F6 para ordenar, y F9 para matar un proceso.

Terminar procesos: kill

A veces un programa se queda colgado o necesitas detener algo que está corriendo. Para eso usas kill seguido del PID del proceso:

Terminal window
# Primero, encuentra el PID del proceso
ps aux | grep "nombre-del-programa"
# Terminar el proceso de forma amable (SIGTERM)
kill 1234
# Si no responde, forzar la terminación (SIGKILL)
kill -9 1234

La diferencia entre kill y kill -9 es importante:

SeñalNúmero¿Qué hace?
SIGTERM15 (por defecto)Le pide al proceso que termine. El proceso puede guardar datos y cerrar correctamente
SIGKILL9Fuerza la terminación inmediata. El proceso no puede ignorar esta señal ni guardar nada
⚠️

Usa kill -9 solo como último recurso

Siempre intenta primero kill PID (sin el -9). Esto le da oportunidad al programa de cerrar correctamente, guardar archivos y liberar recursos. Solo usa kill -9 PID si el proceso no responde después de unos segundos. Matar un proceso con -9 puede causar pérdida de datos o archivos corruptos.

Si no quieres buscar el PID manualmente, puedes terminar procesos por su nombre:

Terminal window
# Terminar todos los procesos llamados "node"
killall node
# Terminar un proceso que coincida con un patrón
pkill -f "python script.py"
⚠️

Cuidado con killall

killall termina TODOS los procesos que coincidan con ese nombre. Si tienes 5 procesos de Node.js corriendo, killall node los termina todos. Asegúrate de que quieres terminar todos antes de usarlo.

Procesos en segundo plano

Normalmente, cuando ejecutas un comando, la terminal se “bloquea” hasta que el comando termina. No puedes escribir nada más hasta que finalice. Pero puedes ejecutar procesos en segundo plano para que la terminal quede libre:

Terminal window
# El & al final ejecuta el comando en segundo plano
sleep 60 &
# [1] 5678 ← [número de job] PID
# La terminal queda libre para seguir trabajando

Veamos los comandos para gestionar procesos en segundo plano:

Terminal window
# Ver los procesos en segundo plano de esta terminal
jobs
# [1]+ Running sleep 60 &
# Traer un proceso al frente (vuelve a bloquear la terminal)
fg %1
# Pausar el proceso actual: presiona Ctrl+Z
# [1]+ Stopped sleep 60
# Continuar el proceso pausado, pero en segundo plano
bg %1

Ejemplo práctico paso a paso

Imagina que quieres levantar un servidor web simple mientras sigues trabajando en la terminal:

Terminal window
# Iniciar un servidor HTTP en segundo plano
python3 -m http.server 8000 &
# [1] 5678
# Verificar que está corriendo
jobs
# [1]+ Running python3 -m http.server 8000 &
# Seguir trabajando normalmente...
ls
pwd
# Cuando quieras detenerlo, tráelo al frente y usa Ctrl+C
fg %1
# Ctrl+C para detenerlo

Atajos de teclado importantes

Estos atajos funcionan con cualquier proceso que esté corriendo en tu terminal:

Atajo¿Qué hace?
Ctrl + CInterrumpe (mata) el proceso que está corriendo en primer plano
Ctrl + ZPausa el proceso actual y te devuelve al prompt
Ctrl + DEnvía señal de “fin de entrada” (cierra la terminal si no hay nada corriendo)
💡

Ctrl+C es tu botón de emergencia

Si algún comando se queda corriendo y no termina, o si ves que algo no va bien, presiona Ctrl + C. Esto interrumpe la mayoría de los programas inmediatamente. Es el equivalente a “forzar cierre” pero de forma segura. Úsalo sin miedo.

Resumen de comandos

Comando Descripción
ps aux Listar todos los procesos del sistema
ps aux | grep nombre Buscar un proceso específico
top Monitor de procesos en tiempo real
htop Monitor mejorado (necesita instalación)
kill PID Terminar proceso de forma amable
kill -9 PID Forzar terminación (último recurso)
killall nombre Terminar todos los procesos con ese nombre
comando & Ejecutar en segundo plano
jobs Ver procesos en segundo plano
fg %N Traer proceso N al frente
bg %N Continuar proceso N en segundo plano
Ctrl+C Interrumpir el proceso actual
Ctrl+Z Pausar el proceso actual

Ejercicios del módulo

  1. Ejecuta ps (sin flags). ¿Cuántos procesos ves? ¿Qué procesos son?
  2. Ahora ejecuta ps aux. ¿Cuántos procesos hay en total? Usa ps aux | wc -l para contarlos.
  3. Busca si tienes algún proceso de Bash corriendo: ps aux | grep "bash". ¿Cuántos aparecen?
  4. Ejecuta top y observa qué procesos usan más CPU y memoria. Presiona q para salir.
  5. Si tienes htop instalado, ejecútalo y compara con top. Si no lo tienes, instálalo con sudo apt install htop.
  6. Ejecuta sleep 30 & para crear un proceso en segundo plano. Usa jobs para verificar que está corriendo. Luego usa fg %1 para traerlo al frente y Ctrl+C para detenerlo.
  7. Ejecuta sleep 120 &. Busca su PID con ps aux | grep sleep. Termínalo con kill PID.
  8. Ejecuta sleep 200 &, luego otro sleep 300 &. Usa jobs para ver ambos. Mata el segundo con kill %2.
  9. Ejecuta cat (sin argumentos; se queda esperando entrada). Practica usar Ctrl+C para interrumpirlo. Luego ejecútalo de nuevo y usa Ctrl+Z para pausarlo. ¿Qué diferencia hay?
  10. Desafío: Ejecuta python3 -m http.server 9000 & (o cualquier comando de larga duración), verifica que está corriendo con jobs y ps, y luego termínalo usando su PID.
08

Bash scripting

¿Qué es un script de Bash?

Hasta ahora has escrito comandos uno por uno en la terminal. Un script es simplemente un archivo de texto que contiene una serie de comandos que se ejecutan en secuencia. En lugar de escribir 10 comandos a mano, los pones todos en un archivo y lo ejecutas una sola vez.

Piensa en un script como una receta de cocina: es una lista de instrucciones paso a paso que el computador sigue automáticamente. Los scripts son increíblemente útiles para automatizar tareas repetitivas, como hacer respaldos, procesar archivos de datos, o configurar un entorno de trabajo.

¿Por qué Bash si ya existe Python y R?

Si vienes del mundo de ciencia de datos, probablemente te preguntas: ¿para qué aprender Bash scripting si puedo hacer todo en Python o R? La respuesta es que Bash no reemplaza a esos lenguajes, los coordina. Cada uno tiene su rol:

  • Python/R: análisis, estadísticas, modelos, visualizaciones
  • Bash: automatizar, conectar, mover archivos, preparar datos, orquestar

En la práctica, un flujo de trabajo real de ciencia de datos se ve así:

pipeline-datos.sh
#!/bin/bash
echo "=== Pipeline de análisis de datos ==="
echo "Inicio: $(date)"
# 1. Descargar los datos frescos
echo "Descargando datos..."
curl -s -o datos_raw.csv https://api.ejemplo.com/datos/export
# 2. Limpiar y transformar con Python
echo "Limpiando datos con Python..."
python3 limpiar_datos.py datos_raw.csv datos_limpios.csv
# 3. Análisis estadístico con R
echo "Ejecutando análisis en R..."
Rscript analisis_estadistico.R datos_limpios.csv resultados/
# 4. Generar reporte
echo "Generando reporte..."
python3 generar_reporte.py resultados/ reporte_final.html
echo "Pipeline completado: $(date)"
echo "Reporte disponible en: reporte_final.html"

Bash es el director de orquesta: descarga datos, llama a Python para limpiarlos, llama a R para analizarlos, y junta todo. Este patrón es la forma estándar de trabajar en Bioinformática, Data Science y DevOps.

💡

Ejemplo real: Bioinformática

En bioinformática, un pipeline típico ejecuta una docena de herramientas diferentes en secuencia: descarga secuencias genómicas, las alinea con una herramienta en C++, las filtra con Python, hace estadísticas con R, y genera reportes en HTML. Todo coordinado por un script de Bash. Sin Bash, tendrías que ejecutar cada paso manualmente y acordarte del orden exacto.

Otro ejemplo más simple pero muy útil: preparar tu entorno de trabajo cada día:

iniciar-proyecto.sh
#!/bin/bash
# Script para iniciar tu día de trabajo en un proyecto de datos
echo "Preparando entorno de trabajo..."
# Activar el entorno virtual de Python
source ~/envs/mi-proyecto/bin/activate
# Ir al directorio del proyecto
cd ~/proyectos/analisis-salud
# Descargar datos actualizados
echo "Descargando datos del día..."
python3 descargar_datos.py
# Abrir Jupyter Notebook
echo "Abriendo Jupyter..."
jupyter notebook &
echo "¡Todo listo! Jupyter se abrió en tu navegador."

En lugar de recordar y escribir 5 comandos cada mañana, ejecutas ./iniciar-proyecto.sh y todo se prepara solo.

Tu primer script

Vamos a crear un script simple paso a paso. Abre Nano y crea un archivo llamado hola.sh:

Terminal window
nano hola.sh

Escribe lo siguiente:

hola.sh
#!/bin/bash
# Mi primer script de Bash
echo "¡Hola desde mi script!"
echo "Hoy es $(date)"
echo "Estás en: $(pwd)"

Guarda con Ctrl + O + Enter y sal con Ctrl + X.

Antes de poder ejecutarlo, necesitas dos pasos:

Terminal window
# Paso 1: Dar permiso de ejecución
chmod +x hola.sh
# Paso 2: Ejecutar el script
./hola.sh

El shebang: #!/bin/bash

La primera línea #!/bin/bash se llama shebang (o hashbang). Es la línea más importante de cualquier script porque le dice al sistema operativo qué programa debe usar para interpretar las instrucciones que siguen.

#!/bin/bash ← "Usa Bash para ejecutar este script"

Sin el shebang, el sistema podría intentar ejecutar tu script con el shell equivocado, o directamente no saber qué hacer con él. Siempre incluye el shebang como primera línea.

El shebang no es exclusivo de Bash. Esto es lo que hace tan poderoso el concepto: puedes tener scripts en diferentes lenguajes y el sistema sabe cómo ejecutar cada uno:

#!/bin/bash # Script de Bash
#!/usr/bin/env python3 # Script de Python
#!/usr/bin/env Rscript # Script de R
#!/usr/bin/env node # Script de Node.js

¿Por qué /usr/bin/env?

Para Python, R y otros lenguajes, es mejor usar #!/usr/bin/env python3 en vez de #!/usr/bin/python3. La versión con env busca el programa en tu PATH, así funciona aunque Python esté instalado en una ruta diferente (como en un entorno virtual). Para Bash usamos #!/bin/bash directamente porque Bash siempre está en /bin/bash en sistemas Linux.

Rutas al ejecutar scripts: ./ y por qué importa

¿Por qué escribimos ./hola.sh y no simplemente hola.sh? Este es un punto que confunde a muchos al principio, pero es fundamental entenderlo.

Cuando escribes un comando en la terminal, el sistema lo busca en una lista de carpetas predefinidas (el PATH). Puedes ver esas carpetas con:

/sbin
echo $PATH

Si escribes ls, la terminal busca en esas carpetas, encuentra /usr/bin/ls, y lo ejecuta. Pero tu script hola.sh no está en ninguna de esas carpetas — está en tu directorio actual. Por eso necesitas decirle explícitamente dónde está:

Terminal window
# Esto NO funciona (busca hola.sh en el PATH del sistema)
hola.sh
# Error: command not found
# Esto SÍ funciona (el ./ significa "en el directorio actual")
./hola.sh
# Esto también funciona (ruta completa)
/home/paulo/scripts/hola.sh
# Y esto también (ruta relativa desde otro lugar)
../scripts/hola.sh

Repasemos los tipos de rutas, porque entender esto te ahorrará muchos dolores de cabeza:

Ruta absoluta: empieza desde la raíz del sistema (/). Siempre funciona sin importar dónde estés:

Terminal window
/home/paulo/proyectos/analisis/script.sh
/home/paulo/datos/pacientes.csv

Ruta relativa: parte desde tu directorio actual. Cambia según dónde estés:

Terminal window
./script.sh # En el directorio actual
../datos/pacientes.csv # Un nivel arriba, luego en datos/
scripts/procesar.sh # Dentro de la subcarpeta scripts/

Atajos útiles:

Terminal window
. # Directorio actual
.. # Directorio padre (un nivel arriba)
~ # Tu directorio home (/home/tu-usuario)
⚠️

Las rutas dentro de un script son relativas a DONDE lo ejecutas

Este es uno de los errores más comunes. Si tu script hace referencia a datos/archivo.csv, esa ruta es relativa al directorio desde donde ejecutas el script, no a donde está el script. Ejemplo:

Terminal window
# Tu script está en ~/proyectos/scripts/procesar.sh
# Y dentro tiene: python3 limpiar.py datos/raw.csv
# Si lo ejecutas desde ~/proyectos/scripts/
cd ~/proyectos/scripts/
./procesar.sh # Busca datos/raw.csv dentro de scripts/ ← ¡NO EXISTE!
# Si lo ejecutas desde ~/proyectos/
cd ~/proyectos/
./scripts/procesar.sh # Busca datos/raw.csv dentro de proyectos/ ← ¡CORRECTO!

Para evitar este problema, usa rutas absolutas dentro de tus scripts, o usa este truco al inicio del script para cambiar al directorio donde está el archivo:

#!/bin/bash
# Ir al directorio donde está este script
cd "$(dirname "$0")"

Veamos un ejemplo práctico. Imagina esta estructura de proyecto:

mi-proyecto/
├── scripts/
│ ├── limpiar.sh
│ └── analizar.sh
├── datos/
│ ├── raw/
│ │ └── encuesta.csv
│ └── procesados/
└── resultados/

Dentro de limpiar.sh, podrías escribir las rutas de dos formas:

scripts/limpiar.sh — MAL (rutas frágiles)
#!/bin/bash
# Esto solo funciona si ejecutas desde mi-proyecto/
python3 scripts/limpiar_datos.py datos/raw/encuesta.csv datos/procesados/encuesta_limpia.csv
scripts/limpiar.sh — BIEN (rutas robustas)
#!/bin/bash
# Primero nos ubicamos en la raíz del proyecto
cd "$(dirname "$0")/.."
# Ahora las rutas son predecibles
python3 scripts/limpiar_datos.py datos/raw/encuesta.csv datos/procesados/encuesta_limpia.csv
echo "Datos procesados en: $(pwd)/datos/procesados/"

La línea cd "$(dirname "$0")/.." hace lo siguiente:

  • $0 = la ruta con la que se llamó al script (ej: ./scripts/limpiar.sh)
  • dirname "$0" = el directorio donde está el script (ej: ./scripts)
  • /.." = subir un nivel (al directorio del proyecto)

Así el script siempre funciona sin importar desde dónde lo ejecutes.

Variables

Las variables te permiten guardar información para usarla más adelante. En Bash, asignas una variable con el signo = y la usas poniendo $ antes del nombre:

variables.sh
#!/bin/bash
# Asignar variables
nombre="Paulo"
edad=30
fecha=$(date +%Y-%m-%d)
# Usar variables con $
echo "Hola, $nombre"
echo "Tienes $edad años"
echo "Fecha: $fecha"
# Usar llaves para delimitar el nombre de la variable
echo "Archivo: ${nombre}_backup.txt"
⚠️

Sin espacios alrededor del =

En Bash, la asignación de variables no puede tener espacios alrededor del =. Esto es correcto: nombre="Paulo". Esto dará error: nombre = "Paulo". Es uno de los errores más comunes cuando empiezas con scripting.

Las llaves ${nombre} son necesarias cuando la variable va pegada a otro texto. Sin las llaves, $nombre_backup buscaría una variable llamada nombre_backup (que no existe), en lugar de usar la variable nombre seguida del texto _backup.

Variables especiales

Bash tiene variables especiales que se crean automáticamente. Son especialmente útiles cuando tu script recibe información desde la línea de comandos:

VariableSignificado
$0El nombre del script
$1, $2, ...Los argumentos que le pasaste al script
$#La cantidad de argumentos
$@Todos los argumentos juntos
$?El código de salida del último comando (0 = éxito, otro = error)

Veamos cómo funcionan con un ejemplo:

argumentos.sh
#!/bin/bash
echo "Este script se llama: $0"
echo "Primer argumento: $1"
echo "Segundo argumento: $2"
echo "Recibí $# argumentos en total"
echo "Todos los argumentos: $@"
./argumentos.sh
chmod +x argumentos.sh
./argumentos.sh hola mundo
# Primer argumento: hola
# Segundo argumento: mundo
# Recibí 2 argumentos en total
# Todos los argumentos: hola mundo

Leer entrada del usuario con read

A veces quieres que tu script le haga preguntas al usuario y espere su respuesta. Para eso usas read:

interactivo.sh
#!/bin/bash
echo "¿Cómo te llamas?"
read nombre
echo "¿Cuántos años tienes?"
read edad
echo "¡Hola, $nombre! Tienes $edad años."

Puedes hacer lo mismo de forma más compacta con read -p, que muestra el mensaje y espera la respuesta en la misma línea:

Terminal window
read -p "Ingresa tu nombre: " nombre
echo "Hola, $nombre"
# Para passwords (no muestra lo que escribes)
read -sp "Ingresa tu contraseña: " password
echo # salto de línea (porque -s oculta el Enter también)
echo "Contraseña recibida"

Condicionales: tomar decisiones con if

Los condicionales permiten que tu script tome decisiones: “si se cumple esta condición, haz esto; si no, haz esto otro”. La estructura básica es:

Terminal window
if [ condición ]; then
# código si la condición es verdadera
elif [ otra_condición ]; then
# código si la segunda condición es verdadera
else
# código si ninguna condición se cumplió
fi
⚠️

Los espacios son obligatorios

Dentro de los corchetes [ ], los espacios son obligatorios. [ "$edad" -ge 18 ] es correcto. ["$edad" -ge 18] dará error. Esto es uno de los aspectos más confusos de Bash para principiantes, pero es una regla simple: siempre deja un espacio después de [ y antes de ].

Veamos un ejemplo completo:

edad.sh
#!/bin/bash
read -p "¿Cuántos años tienes? " edad
if [ "$edad" -ge 18 ]; then
echo "Eres mayor de edad"
elif [ "$edad" -ge 13 ]; then
echo "Eres adolescente"
else
echo "Eres menor de edad"
fi

Operadores de comparación para números

OperadorSignificadoEjemplo
-eqIgual a[ "$a" -eq 5 ]
-neNo igual a[ "$a" -ne 0 ]
-gtMayor que[ "$a" -gt 10 ]
-geMayor o igual que[ "$a" -ge 18 ]
-ltMenor que[ "$a" -lt 0 ]
-leMenor o igual que[ "$a" -le 100 ]

Operadores para texto (strings)

OperadorSignificadoEjemplo
=Textos iguales[ "$nombre" = "Paulo" ]
!=Textos diferentes[ "$respuesta" != "no" ]
-zTexto vacío[ -z "$variable" ]
-nTexto no vacío[ -n "$variable" ]

Operadores para archivos

Estos son especialmente útiles para scripts que trabajan con archivos:

OperadorSignificadoEjemplo
-fExiste y es un archivo[ -f "datos.csv" ]
-dExiste y es un directorio[ -d "carpeta" ]
-eExiste (archivo o directorio)[ -e "algo" ]
-rTiene permiso de lectura[ -r "archivo" ]
-wTiene permiso de escritura[ -w "archivo" ]
-xTiene permiso de ejecución[ -x "script.sh" ]
verificar.sh
#!/bin/bash
archivo=$1
# Verificar que se proporcionó un argumento
if [ -z "$archivo" ]; then
echo "Uso: $0 <nombre-de-archivo>"
echo "Ejemplo: $0 datos.csv"
exit 1
fi
# Verificar qué es
if [ -f "$archivo" ]; then
lineas=$(wc -l < "$archivo")
echo "'$archivo' es un archivo con $lineas líneas"
elif [ -d "$archivo" ]; then
echo "'$archivo' es un directorio"
else
echo "'$archivo' no existe"
fi

Bucle for: repetir acciones

El bucle for repite una acción para cada elemento de una lista. Es como decir “para cada X, haz Y”:

for-basico.sh
#!/bin/bash
# Iterar sobre una lista de palabras
for fruta in manzana pera naranja; do
echo "Fruta: $fruta"
done
# Fruta: manzana
# Fruta: pera
# Fruta: naranja

Los usos más prácticos de for son recorrer archivos y rangos numéricos:

Terminal window
# Procesar todos los archivos .txt del directorio
for archivo in *.txt; do
echo "Procesando: $archivo"
wc -l "$archivo"
done
# Contar del 1 al 5
for i in {1..5}; do
echo "Número: $i"
done
# Estilo C (si vienes de otro lenguaje)
for ((i = 0; i < 5; i++)); do
echo "Índice: $i"
done

Ejemplo práctico: renombrar archivos en lote

renombrar.sh
#!/bin/bash
# Renombrar todos los .txt a .md
for archivo in *.txt; do
# Verificar que realmente hay archivos .txt
[ -f "$archivo" ] || continue
nuevo="${archivo%.txt}.md"
mv "$archivo" "$nuevo"
echo "Renombrado: $archivo$nuevo"
done

La expresión ${archivo%.txt} elimina .txt del final del nombre. Luego le agregamos .md. Es una forma muy útil de manipular nombres de archivo en Bash.

Bucle while: repetir mientras se cumpla una condición

A diferencia de for (que recorre una lista), while repite una acción mientras una condición sea verdadera:

while.sh
#!/bin/bash
# Contador simple
contador=1
while [ "$contador" -le 5 ]; do
echo "Contando: $contador"
((contador++))
done

Un uso muy práctico de while es leer un archivo línea por línea:

Terminal window
# Leer cada línea de un archivo
while IFS= read -r linea; do
echo "Línea: $linea"
done < archivo.txt

Menú interactivo con while y case

Este es un patrón muy común en scripts de Bash: un menú que se repite hasta que el usuario elige salir:

menu.sh
#!/bin/bash
while true; do
echo ""
echo "=== MENÚ ==="
echo "1) Mostrar fecha"
echo "2) Listar archivos"
echo "3) Uso de disco"
echo "4) Salir"
read -p "Elige una opción: " opcion
case $opcion in
1) date ;;
2) ls -la ;;
3) df -h ;;
4) echo "¡Adiós!"; break ;;
*) echo "Opción no válida, intenta de nuevo" ;;
esac
done

case es la versión Bash de un “switch”: compara el valor de $opcion con cada patrón y ejecuta el código correspondiente. El * es el caso por defecto (si no coincide con nada).

Funciones: reutilizar código

Las funciones te permiten agrupar comandos bajo un nombre y reutilizarlos. Si te encuentras repitiendo el mismo bloque de código varias veces, ponlo en una función:

funciones.sh
#!/bin/bash
# Definir una función
saludar() {
echo "¡Hola, $1!"
}
# Llamar a la función
saludar "Paulo"
saludar "María"
# ¡Hola, Paulo!
# ¡Hola, María!

Los argumentos de las funciones funcionan igual que los del script: $1 es el primer argumento, $2 el segundo, etc.

Ejemplo completo: script de respaldo

Ahora vamos a juntar todo lo que aprendimos en un script útil del mundo real. Este script crea un respaldo comprimido de una carpeta:

respaldo.sh
#!/bin/bash
# Script de respaldo simple
# Uso: ./respaldo.sh [directorio-origen] [directorio-destino]
ORIGEN="${1:-.}"
DESTINO="${2:-./respaldo}"
FECHA=$(date +%Y%m%d_%H%M%S)
ARCHIVO="respaldo_${FECHA}.tar.gz"
# Verificar que el directorio origen existe
if [ ! -d "$ORIGEN" ]; then
echo "Error: el directorio '$ORIGEN' no existe"
exit 1
fi
# Crear directorio destino si no existe
mkdir -p "$DESTINO"
echo "Creando respaldo de '$ORIGEN'..."
# Crear el archivo comprimido
tar -czf "${DESTINO}/${ARCHIVO}" "$ORIGEN"
# Verificar si el comando tuvo éxito
if [ $? -eq 0 ]; then
tamano=$(du -h "${DESTINO}/${ARCHIVO}" | cut -f1)
echo "Respaldo creado exitosamente:"
echo " Archivo: ${DESTINO}/${ARCHIVO}"
echo " Tamaño: ${tamano}"
else
echo "Error al crear el respaldo"
exit 1
fi
Terminal window
chmod +x respaldo.sh
./respaldo.sh ./mi-proyecto ./backups
# Creando respaldo de './mi-proyecto'...
# Respaldo creado exitosamente:
# Archivo: ./backups/respaldo_20260214_153000.tar.gz
# Tamaño: 2.5M

Analicemos las partes nuevas:

  • ${1:-.} significa “usa el primer argumento, y si no hay ninguno, usa .” (directorio actual).
  • tar -czf crea un archivo comprimido (.tar.gz). -c = crear, -z = comprimir con gzip, -f = nombre del archivo.
  • $? contiene el código de salida del último comando. 0 significa éxito, cualquier otro número significa error.

Bash como herramienta de ciencia de datos

Ya vimos cómo Bash coordina herramientas. Pero Bash también puede hacer procesamiento de datos básico por sí solo, sin necesidad de Python o R. Esto es útil para exploración rápida, limpieza preliminar, o cuando trabajas en un servidor sin entorno gráfico.

Explorar un CSV desde la terminal

explorar-csv.sh
#!/bin/bash
# Script para exploración rápida de un archivo CSV
archivo="${1:?Uso: $0 archivo.csv}"
if [ ! -f "$archivo" ]; then
echo "Error: '$archivo' no existe"
exit 1
fi
echo "=== Exploración de $archivo ==="
echo ""
# ¿Cuántas filas tiene? (restamos 1 por el encabezado)
total=$(wc -l < "$archivo")
filas=$((total - 1))
echo "Filas de datos: $filas"
# ¿Cuántas columnas?
columnas=$(head -1 "$archivo" | tr ',' '\n' | wc -l)
echo "Columnas: $columnas"
# Mostrar los nombres de las columnas
echo ""
echo "Nombres de columnas:"
head -1 "$archivo" | tr ',' '\n' | nl
# Primeras 5 filas
echo ""
echo "Primeras 5 filas:"
head -6 "$archivo" | column -t -s ','
# Tamaño del archivo
tamano=$(du -h "$archivo" | cut -f1)
echo ""
echo "Tamaño: $tamano"
Terminal window
chmod +x explorar-csv.sh
./explorar-csv.sh datos_pacientes.csv
# === Exploración de datos_pacientes.csv ===
#
# Filas de datos: 1523
# Columnas: 8
#
# Nombres de columnas:
# 1 id
# 2 nombre
# 3 edad
# 4 diagnostico
# ...

Procesar múltiples archivos de datos

Imagina que recibes datos mensuales en archivos separados y necesitas unirlos:

unir-datos.sh
#!/bin/bash
# Unir múltiples CSV en uno solo (mismo formato, con encabezado)
directorio="${1:-.}"
salida="${2:-datos_combinados.csv}"
# Tomar el encabezado del primer archivo
primer_archivo=$(ls "$directorio"/*.csv 2>/dev/null | head -1)
if [ -z "$primer_archivo" ]; then
echo "No se encontraron archivos CSV en '$directorio'"
exit 1
fi
# Escribir encabezado
head -1 "$primer_archivo" > "$salida"
# Agregar datos de todos los archivos (sin encabezado)
for archivo in "$directorio"/*.csv; do
tail -n +2 "$archivo" >> "$salida"
echo " Agregado: $archivo ($(tail -n +2 "$archivo" | wc -l) filas)"
done
total=$(tail -n +2 "$salida" | wc -l)
echo "Archivo combinado: $salida ($total filas totales)"

¿Cuándo usar Bash vs Python para datos?

Usa Bash cuando necesites: exploración rápida (cuántas filas, qué columnas), unir/dividir archivos, renombrar archivos en lote, automatizar pipelines, descargar datos.

Usa Python/R cuando necesites: análisis estadístico, limpieza compleja, visualizaciones, machine learning, manipulación avanzada de DataFrames.

La combinación de ambos es lo más poderoso: Bash prepara y orquesta, Python/R analiza.

Ejercicios del módulo

  1. Crea un script saludo.sh que reciba un nombre como argumento ($1) y diga “¡Hola, [nombre]!”. Si no recibe argumento, que diga “¡Hola, mundo!”.
  2. Crea un script info.sh que muestre tu usuario, la fecha, el directorio actual y cuántos archivos hay en él.
  3. Crea un script que reciba un número como argumento y diga si es positivo, negativo o cero.
  4. Crea un script con read -p que pida el nombre de un archivo y diga si existe o no (usa [ -f "$archivo" ]).
  5. Crea un script con un bucle for que cree 5 archivos: archivo1.txt, archivo2.txt, …, archivo5.txt.
  6. Crea un script que recorra todos los archivos .txt del directorio actual y muestre cuántas líneas tiene cada uno.
  7. Crea un menú interactivo con while y case que tenga al menos 3 opciones útiles (fecha, archivos, espacio en disco, etc.).
  8. Modifica el script de respaldo del ejemplo para que muestre un mensaje de confirmación antes de crear el respaldo (“¿Estás seguro? (s/n)”).
  9. Crea una función contar_archivos que reciba un directorio como argumento y diga cuántos archivos contiene.
  10. Crea un script explorar.sh que reciba un archivo CSV como argumento y muestre: número de filas, número de columnas, nombres de las columnas, y las primeras 3 filas de datos.
  11. Desafío 1: Crea un script que reciba una extensión como argumento (ej: txt) y cuente cuántos archivos con esa extensión hay en el directorio actual y sus subdirectorios (usa find).
  12. Desafío 2: Crea un mini-pipeline: un script que (1) cree un archivo CSV de prueba con datos inventados, (2) llame a otro script que cuente las filas y columnas, y (3) muestre un resumen final. Practica la coordinación entre scripts.
09

Automatización con Cron

¿Qué es Cron?

Imagina que necesitas hacer un respaldo de tus datos todos los días a las 3 de la mañana, o limpiar archivos temporales cada semana. No vas a estar despierto para ejecutar esos comandos manualmente. Para eso existe Cron: un servicio de Linux que ejecuta tareas automáticamente en los horarios que tú definas.

Cron funciona como un despertador programable: tú le dices “ejecuta este comando a esta hora” y él se encarga de hacerlo, sin importar si estás frente al computador o no.

El crontab: tu agenda de tareas

Cada usuario tiene su propio crontab (tabla de cron), que es el archivo donde defines tus tareas programadas. Los comandos para gestionarlo son simples:

Terminal window
# Ver tus tareas programadas actuales
crontab -l
# Editar tu crontab (abrir el editor para agregar/modificar tareas)
crontab -e
# Eliminar TODAS tus tareas programadas
crontab -r
⚠️

Cuidado con crontab -r

El comando crontab -r elimina todas tus tareas programadas sin pedir confirmación. Si solo quieres eliminar una tarea, usa crontab -e y borra la línea correspondiente. Es muy fácil confundir -e (editar) con -r (remover) porque están al lado en el teclado.

💡

Primera vez con crontab -e

La primera vez que ejecutes crontab -e, te pedirá elegir un editor de texto. Selecciona nano (generalmente es la opción 1). Si por accidente seleccionas Vim y no sabes usarlo, presiona Esc, escribe :q! y Enter para salir, luego ejecuta select-editor para cambiar el editor.

La sintaxis de Cron paso a paso

Cada línea del crontab tiene dos partes: cuándo ejecutar (5 campos de tiempo) y qué ejecutar (el comando). La estructura es:

┌───────── minuto (0-59)
│ ┌─────── hora (0-23)
│ │ ┌───── día del mes (1-31)
│ │ │ ┌─── mes (1-12)
│ │ │ │ ┌─ día de la semana (0-7, donde 0 y 7 = domingo)
│ │ │ │ │
* * * * * comando-a-ejecutar

El asterisco * significa “todos los valores posibles”. Así que * * * * * significa “cada minuto de cada hora de cada día de cada mes de cada día de la semana” (o sea, cada minuto).

Veamos los caracteres especiales que puedes usar:

CarácterSignificadoEjemplo
*Cualquier valor* * * * * = cada minuto
,Lista de valores0,15,30,45 * * * * = minutos 0, 15, 30 y 45
-Rango de valores0 9-17 * * * = cada hora de 9 AM a 5 PM
/Cada N unidades*/5 * * * * = cada 5 minutos

Ejemplos prácticos explicados

Veamos algunos ejemplos comunes, traduciéndolos a español:

crontab -e
# Cada minuto (útil para probar que cron funciona)
* * * * * echo "test $(date)" >> /tmp/cron-test.log
# Todos los días a las 2:30 AM
# (minuto 30, hora 2, cualquier día, cualquier mes, cualquier día de semana)
30 2 * * * /home/usuario/scripts/respaldo.sh
# Cada lunes a las 9:00 AM
# (minuto 0, hora 9, cualquier día del mes, cualquier mes, día 1=lunes)
0 9 * * 1 /home/usuario/scripts/reporte-semanal.sh
# Cada 15 minutos
*/15 * * * * /home/usuario/scripts/verificar-servicio.sh
# El primer día de cada mes a medianoche
0 0 1 * * /home/usuario/scripts/limpieza-mensual.sh
# De lunes a viernes a las 8:00 AM
0 8 * * 1-5 /home/usuario/scripts/recordatorio.sh
# Cada 6 horas (a las 0, 6, 12, 18)
0 */6 * * * /home/usuario/scripts/sincronizar.sh

Probador de expresiones cron

Si no estás seguro de que tu expresión cron hace lo que quieres, usa crontab.guru. Es una herramienta web gratuita donde escribes la expresión y te dice en español cuándo se ejecutará. Úsala siempre antes de agregar una tarea a tu crontab.

Errores comunes y buenas prácticas

Cron ejecuta las tareas en un entorno mínimo: no carga tu archivo .bashrc, no tiene las mismas variables de entorno que tu terminal, y no sabe dónde están tus programas a menos que se lo digas explícitamente. Esto causa la mayoría de los problemas con cron.

Siempre usa rutas absolutas:

Terminal window
# MAL: cron no sabe dónde está "mi-script.sh"
* * * * * mi-script.sh
# BIEN: ruta completa al script
* * * * * /home/usuario/scripts/mi-script.sh
# MAL: cron podría no encontrar python3
* * * * * python3 tarea.py
# BIEN: ruta completa a python y al script
* * * * * /usr/bin/python3 /home/usuario/scripts/tarea.py

Siempre redirige la salida a un log para poder investigar si algo sale mal:

Terminal window
# Sin log: si hay un error, nunca te enterarás
0 3 * * * /home/usuario/scripts/respaldo.sh
# Con log: guardas la salida y los errores
0 3 * * * /home/usuario/scripts/respaldo.sh >> /home/usuario/logs/respaldo.log 2>&1

El 2>&1 al final significa “envía los errores al mismo lugar que la salida normal”. Así tanto los mensajes normales como los errores quedan guardados en el log.

⚠️

Los 3 errores más comunes con cron

  1. Usar rutas relativas: Siempre usa rutas absolutas para scripts y programas.
  2. No dar permisos de ejecución: Tu script necesita chmod +x para que cron pueda ejecutarlo.
  3. No redirigir la salida: Sin un log, no sabrás si tu tarea falló o qué error produjo.

Script de ejemplo para usar con Cron

Veamos un ejemplo completo de un script diseñado para ser ejecutado por cron:

limpieza.sh
#!/bin/bash
# Script de limpieza: elimina archivos temporales mayores a 7 días
# Diseñado para ejecutarse con cron
LOG="$HOME/logs/limpieza.log"
mkdir -p "$HOME/logs"
DIR="/tmp"
echo "=== Limpieza $(date) ===" >> "$LOG"
# Encontrar y contar archivos viejos
archivos=$(find "$DIR" -type f -mtime +7 -name "*.tmp" 2>/dev/null)
if [ -n "$archivos" ]; then
cantidad=$(echo "$archivos" | wc -l)
echo "Encontrados $cantidad archivos para eliminar" >> "$LOG"
echo "$archivos" | while read -r f; do
rm "$f" && echo " Eliminado: $f" >> "$LOG"
done
else
echo "No hay archivos para limpiar" >> "$LOG"
fi
echo "=== Fin ===" >> "$LOG"
Terminal window
# Dar permisos de ejecución
chmod +x limpieza.sh
# Agregar al crontab para ejecutar todos los días a las 3 AM
crontab -e
# Agregar esta línea:
# 0 3 * * * /home/usuario/scripts/limpieza.sh

Verificar que cron funciona

Si acabas de configurar una tarea cron y quieres verificar que funciona, sigue estos pasos:

Terminal window
# 1. Verificar que el servicio cron está corriendo
systemctl status cron
# Debería decir "active (running)"
# 2. Agregar una tarea de prueba que se ejecute cada minuto
crontab -e
# Agregar: * * * * * echo "$(date) - cron funciona" >> /tmp/cron-test.log
# 3. Esperar un minuto y verificar
cat /tmp/cron-test.log
# Deberías ver una línea con la fecha
# 4. ¡MUY IMPORTANTE! Eliminar la tarea de prueba
crontab -e
# Borrar la línea de prueba (si la dejas, generará una línea por minuto para siempre)
⚠️

No olvides eliminar las tareas de prueba

Si dejas una tarea que se ejecuta cada minuto, generará datos indefinidamente. Un echo simple no es grave, pero un script que mueve archivos o consume recursos podría causar problemas. Siempre elimina tus tareas de prueba después de verificar.

Resumen

Comando Descripción
crontab -l Ver tus tareas programadas actuales
crontab -e Editar tus tareas programadas
crontab -r Eliminar TODAS las tareas (cuidado)
systemctl status cron Verificar que el servicio cron está activo

Ejercicios del módulo

  1. Ejecuta crontab -l para ver si tienes alguna tarea programada. Si dice “no crontab for user”, es normal.
  2. Ejecuta systemctl status cron para verificar que el servicio está corriendo.
  3. Traduce estas expresiones cron a español (o verifica en crontab.guru):
    • 0 12 * * *
    • 30 8 * * 1-5
    • 0 0 1 * *
    • */10 * * * *
  4. Escribe la expresión cron para: “todos los domingos a las 6 PM”.
  5. Escribe la expresión cron para: “cada 30 minutos, solo entre las 9 AM y las 6 PM, de lunes a viernes”.
  6. Crea una tarea cron de prueba que escriba la fecha actual en /tmp/mi-cron.log cada minuto. Espera 2 minutos y verifica con cat /tmp/mi-cron.log. Luego elimina la tarea de prueba.
  7. Crea el script limpieza.sh del ejemplo. Ejecútalo manualmente primero para verificar que funciona (./limpieza.sh). Luego agrégalo al crontab.
  8. Desafío: Crea un script que registre el uso de disco (df -h) en un archivo de log con fecha y hora, y prográmalo con cron para que se ejecute cada 6 horas.

Ejercicios prácticos finales

Llegaste al final del curso. Estos ejercicios integradores combinan todo lo que has aprendido en los módulos anteriores. Son más complejos que los ejercicios de cada módulo, porque requieren usar múltiples habilidades juntas.

Intenta resolver cada ejercicio por tu cuenta antes de ver la solución. Si te atascas, vuelve al módulo correspondiente para repasar. La práctica es la única forma de internalizar estos conocimientos.

Consejo antes de empezar

Crea una carpeta ejercicios-finales en tu home para trabajar sin ensuciar otros directorios: mkdir ~/ejercicios-finales && cd ~/ejercicios-finales.


Ejercicio 1: Organizador de archivos por extensión

Contexto: Imagina que tienes una carpeta de descargas llena de archivos mezclados: PDFs, imágenes, documentos, etc. Quieres organizarlos automáticamente en subcarpetas según su extensión.

Requisitos:

  • El script recibe un directorio como argumento (o usa el actual por defecto).
  • Verifica que el directorio existe antes de continuar.
  • Crea una subcarpeta para cada extensión encontrada (txt, jpg, pdf, etc.).
  • Mueve cada archivo a su carpeta correspondiente.
  • Muestra un resumen de cuántos archivos movió.

Preparación (para tener archivos de prueba):

Terminal window
mkdir ~/ejercicios-finales/descargas
cd ~/ejercicios-finales/descargas
touch informe.pdf datos.csv foto1.jpg foto2.jpg notas.txt resumen.pdf tabla.csv imagen.png
Ver solución
organizador.sh
#!/bin/bash
directorio="${1:-.}"
if [ ! -d "$directorio" ]; then
echo "Error: '$directorio' no es un directorio válido"
exit 1
fi
cd "$directorio" || exit 1
total=0
for archivo in *.*; do
# Verificar que es un archivo (no una carpeta)
[ -f "$archivo" ] || continue
# Obtener la extensión
extension="${archivo##*.}"
# Crear la carpeta para esa extensión
mkdir -p "$extension"
# Mover el archivo
mv "$archivo" "$extension/"
echo "Movido: $archivo$extension/"
((total++))
done
echo ""
echo "¡Organización completada! Se movieron $total archivos."
Terminal window
chmod +x organizador.sh
./organizador.sh ~/ejercicios-finales/descargas

Ejercicio 2: Monitor de sistema con reporte

Contexto: Necesitas un script que genere un reporte del estado de tu sistema, útil para enviar a alguien que te pregunte “¿cómo está el servidor?”.

Requisitos:

  • Mostrar: usuario actual, hostname, sistema operativo, fecha y hora.
  • Uso de disco del directorio home (en formato legible).
  • Cantidad de procesos en ejecución.
  • Memoria disponible (si el comando está disponible).
  • Los 5 procesos que más CPU consumen.
  • Guardar el reporte en un archivo con la fecha en el nombre.
Ver solución
monitor.sh
#!/bin/bash
FECHA=$(date +%Y%m%d_%H%M%S)
REPORTE="reporte_${FECHA}.txt"
{
echo "========================================"
echo " REPORTE DEL SISTEMA"
echo " Generado: $(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================"
echo ""
echo "--- Información general ---"
echo "Usuario: $(whoami)"
echo "Hostname: $(hostname)"
echo "Sistema: $(uname -s -r)"
echo ""
echo "--- Uso de disco (home) ---"
du -sh ~ 2>/dev/null
echo ""
echo "--- Espacio en disco ---"
df -h / 2>/dev/null
echo ""
echo "--- Procesos activos ---"
echo "Total: $(ps aux | wc -l) procesos"
echo ""
echo "--- Memoria ---"
free -h 2>/dev/null || echo "(comando free no disponible)"
echo ""
echo "--- Top 5 procesos por CPU ---"
ps aux --sort=-%cpu 2>/dev/null | head -6
echo ""
echo "========================================"
} | tee "$REPORTE"
echo ""
echo "Reporte guardado en: $REPORTE"

Ejercicio 3: Buscador de archivos grandes

Contexto: Tu disco se está llenando y necesitas encontrar qué archivos están ocupando más espacio. Este script te ayuda a identificarlos rápidamente.

Requisitos:

  • Recibe un directorio y un tamaño mínimo como argumentos.
  • Si no se proporcionan, usa valores por defecto razonables.
  • Lista los archivos que superen ese tamaño, ordenados de mayor a menor.
  • Muestra el tamaño en formato legible (MB, GB).
  • Al final muestra el total de archivos encontrados y el espacio total que ocupan.
Ver solución
archivos-grandes.sh
#!/bin/bash
directorio="${1:-.}"
tamano_min="${2:-10M}"
if [ ! -d "$directorio" ]; then
echo "Error: '$directorio' no es un directorio válido"
echo "Uso: $0 [directorio] [tamaño-mínimo]"
echo "Ejemplo: $0 /home/usuario 50M"
exit 1
fi
echo "Buscando archivos mayores a $tamano_min en $directorio..."
echo ""
resultados=$(find "$directorio" -type f -size +$tamano_min -exec du -h {} + 2>/dev/null | sort -rh)
if [ -z "$resultados" ]; then
echo "No se encontraron archivos mayores a $tamano_min"
else
echo "TAMAÑO ARCHIVO"
echo "------ -------"
echo "$resultados"
echo ""
total=$(echo "$resultados" | wc -l)
echo "Total: $total archivos encontrados"
fi
Terminal window
chmod +x archivos-grandes.sh
./archivos-grandes.sh /home/usuario 50M

Ejercicio 4: Respaldo automatizado con rotación

Contexto: Necesitas un sistema de respaldo automático que se ejecute diariamente con cron, pero que no acumule respaldos infinitamente (o se llenará el disco).

Requisitos:

  • Crea un respaldo comprimido (.tar.gz) de una carpeta específica.
  • El nombre del archivo incluye la fecha de creación.
  • Elimina automáticamente los respaldos de más de 30 días.
  • Registra todo en un archivo de log.
  • Incluye verificación de errores.
  • Configurar en cron para ejecutar diariamente a las 2 AM.
Ver solución
auto-respaldo.sh
#!/bin/bash
# Configuración (modifica estas rutas según tu sistema)
ORIGEN="/home/usuario/proyectos"
DESTINO="/home/usuario/respaldos"
FECHA=$(date +%Y%m%d)
ARCHIVO="respaldo_${FECHA}.tar.gz"
LOG="/home/usuario/respaldos/respaldo.log"
DIAS_RETENER=30
# Crear directorio de respaldo si no existe
mkdir -p "$DESTINO"
echo "$(date) - Iniciando respaldo..." >> "$LOG"
# Verificar que el directorio origen existe
if [ ! -d "$ORIGEN" ]; then
echo "$(date) - ERROR: '$ORIGEN' no existe" >> "$LOG"
exit 1
fi
# Crear respaldo
tar -czf "${DESTINO}/${ARCHIVO}" "$ORIGEN" 2>> "$LOG"
if [ $? -eq 0 ]; then
tamano=$(du -h "${DESTINO}/${ARCHIVO}" | cut -f1)
echo "$(date) - Respaldo creado: ${ARCHIVO} (${tamano})" >> "$LOG"
else
echo "$(date) - ERROR al crear respaldo" >> "$LOG"
exit 1
fi
# Eliminar respaldos antiguos
eliminados=$(find "$DESTINO" -name "respaldo_*.tar.gz" -mtime +$DIAS_RETENER -delete -print 2>/dev/null)
if [ -n "$eliminados" ]; then
cantidad=$(echo "$eliminados" | wc -l)
echo "$(date) - Eliminados $cantidad respaldos antiguos" >> "$LOG"
fi
echo "$(date) - Respaldo completado exitosamente" >> "$LOG"
echo "---" >> "$LOG"
Terminal window
# Dar permisos y probar manualmente primero
chmod +x auto-respaldo.sh
./auto-respaldo.sh
# Si funciona bien, agregar al cron
crontab -e
# Agregar: 0 2 * * * /home/usuario/scripts/auto-respaldo.sh

Ejercicio 5: Gestor de notas en terminal

Contexto: Quieres una forma rápida de tomar notas desde la terminal, sin abrir ningún otro programa. Este script te da un mini sistema de notas.

Requisitos:

  • Menú interactivo con opciones: crear nota, listar notas, buscar en notas, ver una nota, eliminar nota.
  • Las notas se guardan como archivos individuales en una carpeta dedicada.
  • Cada nota tiene fecha de creación en el nombre del archivo.
  • La búsqueda funciona por contenido (grep).
  • Al eliminar, pide confirmación antes de borrar.
Ver solución
notas.sh
#!/bin/bash
DIRECTORIO="$HOME/mis-notas"
mkdir -p "$DIRECTORIO"
crear_nota() {
read -p "Título de la nota: " titulo
if [ -z "$titulo" ]; then
echo "El título no puede estar vacío"
return
fi
# Convertir espacios a guiones para el nombre de archivo
nombre=$(echo "$titulo" | tr ' ' '-' | tr '[:upper:]' '[:lower:]')
fecha=$(date +%Y%m%d_%H%M%S)
archivo="${DIRECTORIO}/${fecha}_${nombre}.txt"
echo "Escribe el contenido (termina con una línea vacía):"
contenido=""
while IFS= read -r linea; do
[ -z "$linea" ] && break
contenido="${contenido}${linea}\n"
done
printf "# %s\n# Fecha: %s\n\n%b" "$titulo" "$(date)" "$contenido" > "$archivo"
echo ""
echo "Nota guardada: $(basename "$archivo")"
}
listar_notas() {
echo ""
echo "=== TUS NOTAS ==="
archivos=$(ls "$DIRECTORIO"/*.txt 2>/dev/null)
if [ -z "$archivos" ]; then
echo "No hay notas todavía. Crea una con la opción 1."
return
fi
for nota in "$DIRECTORIO"/*.txt; do
nombre=$(basename "$nota")
titulo=$(head -1 "$nota" | sed 's/^# //')
echo " - $nombre"
echo " $titulo"
done
}
ver_nota() {
listar_notas
echo ""
read -p "Nombre del archivo a ver: " archivo
if [ -f "$DIRECTORIO/$archivo" ]; then
echo ""
echo "---"
cat "$DIRECTORIO/$archivo"
echo "---"
else
echo "Archivo no encontrado."
fi
}
buscar_notas() {
read -p "Buscar: " termino
if [ -z "$termino" ]; then
echo "Ingresa un término de búsqueda"
return
fi
echo ""
echo "Resultados para '$termino':"
resultados=$(grep -rl "$termino" "$DIRECTORIO" 2>/dev/null)
if [ -z "$resultados" ]; then
echo " No se encontraron coincidencias."
return
fi
echo "$resultados" | while read -r archivo; do
echo " $(basename "$archivo"):"
grep -n "$termino" "$archivo" | head -3 | sed 's/^/ /'
done
}
eliminar_nota() {
listar_notas
echo ""
read -p "Nombre del archivo a eliminar: " archivo
if [ -f "$DIRECTORIO/$archivo" ]; then
read -p "¿Estás seguro de eliminar '$archivo'? (s/n): " confirmar
if [ "$confirmar" = "s" ]; then
rm "$DIRECTORIO/$archivo"
echo "Nota eliminada."
else
echo "Cancelado."
fi
else
echo "Archivo no encontrado."
fi
}
# Menú principal
echo "=== GESTOR DE NOTAS ==="
echo "Directorio: $DIRECTORIO"
while true; do
echo ""
echo "-------------------"
echo "1) Crear nota"
echo "2) Listar notas"
echo "3) Ver una nota"
echo "4) Buscar en notas"
echo "5) Eliminar nota"
echo "6) Salir"
read -p "Opción: " opcion
case $opcion in
1) crear_nota ;;
2) listar_notas ;;
3) ver_nota ;;
4) buscar_notas ;;
5) eliminar_nota ;;
6) echo "¡Hasta luego!"; exit 0 ;;
*) echo "Opción no válida. Elige entre 1 y 6." ;;
esac
done

Ejercicio 6: Analizador de logs

Contexto: En ciencia de datos, frecuentemente necesitas analizar archivos de texto para extraer patrones. Este ejercicio simula el análisis de un archivo de log de un servidor web.

Requisitos:

  • Primero, genera un archivo de log de ejemplo (se proporciona el comando).
  • Crea un script que analice el log y muestre: total de líneas, cantidad de errores (ERROR), cantidad de advertencias (WARNING), las 5 líneas de error más recientes.
  • Guarda el resumen en un archivo de reporte.

Preparación:

Terminal window
# Generar un log de ejemplo
for i in {1..50}; do
nivel=$((RANDOM % 3))
case $nivel in
0) echo "$(date -d "-$((RANDOM % 100)) minutes" '+%Y-%m-%d %H:%M:%S') [INFO] Operación completada correctamente" ;;
1) echo "$(date -d "-$((RANDOM % 100)) minutes" '+%Y-%m-%d %H:%M:%S') [WARNING] Uso de memoria alto: $((RANDOM % 50 + 50))%" ;;
2) echo "$(date -d "-$((RANDOM % 100)) minutes" '+%Y-%m-%d %H:%M:%S') [ERROR] Conexión rechazada desde 192.168.1.$((RANDOM % 255))" ;;
esac
done > ejemplo.log
Ver solución
analizar-log.sh
#!/bin/bash
archivo="${1:-ejemplo.log}"
reporte="analisis_$(date +%Y%m%d_%H%M%S).txt"
if [ ! -f "$archivo" ]; then
echo "Error: '$archivo' no existe"
echo "Uso: $0 <archivo-de-log>"
exit 1
fi
{
echo "=== ANÁLISIS DE LOG ==="
echo "Archivo: $archivo"
echo "Fecha del análisis: $(date)"
echo ""
total=$(wc -l < "$archivo")
info=$(grep -c "\[INFO\]" "$archivo")
warnings=$(grep -c "\[WARNING\]" "$archivo")
errores=$(grep -c "\[ERROR\]" "$archivo")
echo "--- Resumen ---"
echo "Total de líneas: $total"
echo "INFO: $info"
echo "WARNING: $warnings"
echo "ERROR: $errores"
echo ""
echo "--- Últimos 5 errores ---"
grep "\[ERROR\]" "$archivo" | tail -5
echo ""
echo "--- Últimas 5 advertencias ---"
grep "\[WARNING\]" "$archivo" | tail -5
echo ""
echo "========================"
} | tee "$reporte"
echo ""
echo "Reporte guardado en: $reporte"

Ejercicio 7: Creador de proyectos

Contexto: Cada vez que empiezas un proyecto nuevo de ciencia de datos, necesitas crear la misma estructura de carpetas. Automatiza este proceso.

Requisitos:

  • Recibe el nombre del proyecto como argumento.
  • Crea una estructura estándar: data/raw, data/processed, notebooks, scripts, output.
  • Crea archivos iniciales: README.md con el nombre del proyecto, .gitignore con patrones comunes, y un script setup.sh vacío.
  • Muestra la estructura creada con tree (o con find si tree no está instalado).
Ver solución
crear-proyecto.sh
#!/bin/bash
nombre="${1}"
if [ -z "$nombre" ]; then
read -p "Nombre del proyecto: " nombre
fi
if [ -z "$nombre" ]; then
echo "Error: necesitas proporcionar un nombre de proyecto"
exit 1
fi
if [ -d "$nombre" ]; then
echo "Error: ya existe una carpeta llamada '$nombre'"
exit 1
fi
echo "Creando proyecto '$nombre'..."
# Crear estructura de directorios
mkdir -p "$nombre"/{data/{raw,processed},notebooks,scripts,output}
# Crear README.md
cat > "$nombre/README.md" << EOF
# $nombre
Proyecto de ciencia de datos.
## Estructura
- \`data/raw/\` — Datos crudos (no modificar)
- \`data/processed/\` — Datos procesados
- \`notebooks/\` — Jupyter notebooks
- \`scripts/\` — Scripts de procesamiento
- \`output/\` — Resultados y gráficos
## Fecha de creación
$(date '+%Y-%m-%d')
EOF
# Crear .gitignore
cat > "$nombre/.gitignore" << EOF
# Datos grandes
data/raw/*.csv
data/raw/*.xlsx
*.zip
# Python
__pycache__/
*.pyc
.venv/
# Jupyter
.ipynb_checkpoints/
# Sistema
.DS_Store
Thumbs.db
# Output
output/*.png
output/*.pdf
EOF
# Crear script inicial
cat > "$nombre/scripts/setup.sh" << EOF
#!/bin/bash
echo "Configurando entorno para $nombre..."
# Agrega aquí los comandos de configuración
EOF
chmod +x "$nombre/scripts/setup.sh"
# Mostrar resultado
echo ""
echo "Proyecto creado exitosamente:"
if command -v tree &>/dev/null; then
tree "$nombre"
else
find "$nombre" -type f -o -type d | sort
fi

¿Qué sigue después?

Si completaste estos ejercicios, tienes una base sólida en terminal y Bash. Los siguientes pasos naturales en tu camino de ciencia de datos son:

  • Git: Control de versiones para tus proyectos. Se usa enteramente desde la terminal.
  • SSH: Conectarte a servidores remotos para procesar datos.
  • Docker: Contenedores para reproducir entornos de análisis.
  • Python/R desde la terminal: Ejecutar scripts de análisis directamente.

Recuerda que este curso forma parte del programa de Hazla con Datos. Sigue aprendiendo con los otros cursos del programa.

Siguiente 1. Introducción