Terminal desde cero: rutas, archivos y espacios
Primeros pasos en la terminal de macOS: pwd, ls, cd, mkdir, cp, mv, rm, errores reales, por qué rm -r My Project borró otra carpeta y cp vs. mv medidos.
Serie: curso de línea de comandos 1/6 (principiante). Para quien nunca usó una terminal o solo pega comandos que encuentra en blogs: al terminar esta clase vas a poder moverte entre carpetas, crear, copiar, mover y borrar archivos, y vas a conocer la única regla de comillas que evita que borres la carpeta equivocada.
Mucha gente que empieza a programar recibe la computadora del trabajo el primer día junto con un README que arranca con "abre una terminal y ejecuta…"; a otros les pasa lo mismo en la primera semana del bootcamp o en el primer laboratorio de la universidad. Esta clase es para ellos: explica qué es de verdad esa ventana negra, recorre los primeros comandos en cinco minutos y muestra los mensajes de error exactos que vas a ver cuando algo sale mal. También cubre la trampa en la que cae casi todo el mundo el primer mes: un nombre de carpeta con un espacio, que en nuestra prueba convirtió rm -r My Project en "borra una carpeta completamente distinta".
Si quieres el panorama completo de qué aprender y en qué orden, empieza por la ruta de aprendizaje de programación.
Entorno: macOS 26.6 en una Mac con Apple Silicon (M1 Pro), zsh 5.9 (la shell por defecto) y bash 3.2.57, con las versiones BSD de ls, cp, mv y rm que vienen con macOS. Cada bloque de abajo se ejecutó de verdad. En las salidas acortamos la ruta de la carpeta personal a ~ y reemplazamos el nombre de usuario por demo; no se editó nada más.
Terminal, shell y comando: tres palabras que vas a oír el primer día
- La terminal es la ventana (en Mac, la app llamada Terminal, o iTerm2, o el panel dentro de VS Code). Solo muestra texto y envía lo que tecleas a algún lado.
- La shell es el programa que corre dentro de esa ventana: lee lo que escribes, interpreta qué quisiste decir y arranca otros programas. macOS usa zsh como shell por defecto desde macOS Catalina (10.15); la antigua bash sigue instalada, pero en la versión 3.2, de 2007.
- Un comando es o bien un programa en el disco (
/bin/ls) o algo integrado en la propia shell (cd).typete dice cuál:
~/demo % type ls cd
ls is /bin/ls
cd is a shell builtin
La parte ~/demo % es el prompt. zsh lo imprime para decir "listo, escribe un comando". Muestra dónde estás (~/demo) y termina en % (bash usa $). El prompt nunca lo escribes tú. En el resto de la clase, cada línea que empieza con ~/… % es algo que tecleamos, y las líneas de abajo son lo que respondió.
Tus primeros cinco minutos: pwd, ls, cd, mkdir
pwd (print working directory) te dice en qué carpeta "estás". Cada comando que ejecutas trabaja relativo a esa carpeta, salvo que indiques otra cosa.
~/demo % pwd
~/demo
~/demo % ls
~/demo % mkdir notes
~/demo % mkdir projects/app
mkdir: projects: No such file or directory
~/demo % mkdir -p projects/app/src
~/demo % ls -F
notes/
projects/
ls lista la carpeta; no imprimió nada porque estaba vacía. mkdir crea una carpeta, pero solo un nivel a la vez: projects/app falló porque projects todavía no existía. La opción -p (las opciones son las letras con guion que van después del comando) crea también las carpetas padre que falten. ls -F agrega una / después de las carpetas para que las distingas de los archivos.
Ahora muévete con cd (change directory):
~/demo % cd projects/app
~/demo/projects/app % cd ..
~/demo/projects % cd -
~/demo/projects/app
~/demo/projects/app % cd ~
~ % cd ~/demo
.. es "la carpeta de arriba", cd - te devuelve a donde estabas antes y ~ es tu carpeta personal. Fíjate cómo cambia el prompt después de cada cd: es la forma más rápida de saber dónde estás.
Dos teclas te ahorran casi todo el tipeo: Tab completa el nombre de un archivo o carpeta (escribe cd pro y presiona Tab), y la flecha hacia arriba trae de vuelta el comando anterior.
Rutas: absolutas, relativas, ~, . y ..
Una ruta (path) es la dirección de un archivo. Hay tres formas de escribir la misma dirección:
| Forma | Empieza en | Ejemplo | Se rompe cuando |
|---|---|---|---|
| Absoluta | /, la raíz del disco |
/<your home>/demo/notes/todo.txt (lo que pwd imprime completo) |
el archivo se mueve, o el script corre en otra computadora |
| Relativa a tu carpeta personal | ~, tu carpeta personal |
~/demo/notes/todo.txt |
pones ~ entre comillas (ver abajo) |
| Relativa | la carpeta actual (pwd) |
../notes/todo.txt |
primero haces cd a otro lado |
. significa "esta carpeta" y .. "la carpeta padre". Un detalle sutil: ~ lo expande la shell, y solo cuando no está entre comillas:
~/demo % ls -ld ~/demo
drwxr-xr-x@ 3 demo wheel 96 Nov 12 17:09 ~/demo
~/demo % ls -ld "~/demo"
ls: ~/demo: No such file or directory
~/demo % ls -ld "$HOME/demo"
drwxr-xr-x@ 3 demo wheel 96 Nov 12 17:09 ~/demo
Con comillas, ls buscó una carpeta que se llama literalmente ~. Cuando necesites comillas (por los espacios), usa "$HOME/…" en lugar de "~/…".
Copiar, mover y borrar: cp, mv, rm y los errores que imprimen
~/demo % echo "first line" > notes/todo.txt
~/demo % ls -l notes
total 8
-rw-r--r--@ 1 demo wheel 11 Nov 12 17:09 todo.txt
~/demo % cat notes/todo.md
cat: notes/todo.md: No such file or directory
~/demo % cp notes/todo.txt notes/todo-backup.txt
~/demo % cp notes backup
cp: notes is a directory (not copied).
~/demo % cp -R notes backup
~/demo % mv notes/todo-backup.txt notes/old.txt
~/demo % rm backup
rm: backup: is a directory
~/demo % rmdir backup
rmdir: backup: Directory not empty
~/demo % rm -r backup
Lee estos errores: son precisos. ls -l muestra el formato largo: permisos, dueño, tamaño en bytes (11), fecha y nombre; la @ después de los permisos indica que el archivo tiene atributos extendidos (xattr notes/todo.txt muestra cuál: aquí com.apple.provenance, un atributo de control que macOS agregó por su cuenta; es inofensivo). cp copia un archivo pero rechaza una carpeta salvo que agregues -R (recursivo). mv sirve tanto para renombrar como para mover. rm borra archivos, rechaza carpetas, y rm -r borra una carpeta con todo lo que tenga dentro. rmdir solo elimina carpetas vacías, lo que lo vuelve la opción segura cuando esperas que una carpeta esté vacía.
Importante: rm no usa la papelera. No hay forma de deshacerlo. rm -i pregunta antes (remove a.txt?), un buen hábito para tus primeras semanas.
Error común: los espacios en los nombres borran la carpeta equivocada
Este es el que duele. La shell separa lo que escribes en palabras en cada espacio y después le pasa esas palabras al comando. Un espacio dentro de un nombre se ve exactamente igual que un separador.
~/demo % mkdir My Project
~/demo % ls
My
Project
Queríamos una carpeta y obtuvimos dos. Limpiamos, la creamos bien con comillas y luego intentamos usarla sin comillas:
~/demo % mkdir "My Project"
~/demo % cd My Project
cd: string not in pwd: My
~/demo % cat My Project/plan v2.txt
cat: My: No such file or directory
cat: Project/plan: No such file or directory
cat: v2.txt: No such file or directory
bash 3.2 lo dice de otra forma: bash: cd: My: No such file or directory. Ahora la versión peligrosa. También teníamos una carpeta sin relación llamada Project con un archivo importante dentro:
~/demo % mkdir Project
~/demo % echo keep > Project/important.txt
~/demo % rm -r My Project
rm: My: No such file or directory
~/demo % ls
My Project
~/demo % ls Project
ls: Project: No such file or directory
Lo que pasó en realidad: rm recibió dos palabras, My y Project. My no existía, así que imprimió un error, y es fácil leer ese error como "no pasó nada". Pero Project sí existía, y rm -r la borró con important.txt adentro. La carpeta que queríamos borrar, My Project, sigue ahí. zsh y bash se comportan igual en este caso.
La solución: pon entre comillas todo nombre que pueda tener un espacio, o escapa el espacio con una barra invertida. Las tres formas funcionan:
~/demo % cd "My Project"
~/demo % cd My\ Project
~/demo % cat 'My Project'/'plan v2.txt'
draft
El hábito que evita el accidente: antes de cualquier rm -r, ejecuta ls -d "nombre exacto" con el mismo nombre entre comillas. Si ls muestra exactamente una cosa, presiona la flecha hacia arriba, cambia ls -d por rm -r y ejecútalo. El autocompletado con Tab también ayuda: inserta las barras invertidas por ti.
Dos trampas más pequeñas: un guion al inicio y el # en zsh
Un archivo cuyo nombre empieza con - parece una opción:
~/demo % rm -n.txt
rm: illegal option -- n
usage: rm [-f | -i] [-dIPRrvWx] file ...
unlink [--] file
~/demo % rm -- -n.txt
-- significa "después de esto ya no hay opciones". Escribir ./-n.txt también funciona, porque entonces el nombre empieza con un punto.
Comentarios pegados en zsh. Los blogs suelen escribir ls # list files. En bash, ese # inicia un comentario. En una zsh interactiva de macOS no, salvo que actives la opción:
~/demo % ls # list files
ls: #: No such file or directory
ls: files: No such file or directory
ls: list: No such file or directory
Lo comprobamos con el /etc/zshrc de fábrica y sin configuración personal. Agregar setopt interactive_comments a tu ~/.zshrc hace que zsh trate el # como bash. Dentro de los archivos de script, # siempre es un comentario.
Cómo pedir ayuda: man, no --help
En Linux normalmente puedes escribir ls --help. En Mac los comandos son las versiones BSD y reaccionan así:
~/demo % ls --help
ls: unrecognized option `--help'
usage: ls [-@ABCFGHILOPRSTUWXabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]
~/demo % cp --help
cp: illegal option -- -
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-aclpSsvXx] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-aclpSsvXx] source_file ... target_directory
~/demo % cd --help
cd: no such file or directory: --help
La línea de uso igual sirve como recordatorio. Para el manual completo, usa man ls (espacio para la página siguiente, / para buscar, q para salir). Para saltar directo a una opción:
~/demo % man ls | col -b | grep -n -A2 '^ -a'
98: -a Include directory entries whose names begin with a dot (‘.’).
Los comandos integrados como cd no tienen página de manual propia; en zsh ejecuta man zshbuiltins y en bash help cd.
| Quiero… | Comando | Hábito seguro |
|---|---|---|
| saber dónde estoy | pwd |
lee el prompt después de cada cd |
| ver también los archivos ocultos | ls -la |
los nombres que empiezan con . están ocultos |
| crear carpetas anidadas | mkdir -p a/b/c |
nombres con espacios, entre comillas |
| copiar una carpeta | cp -R src dest |
verifica que dest no exista ya |
| renombrar o mover | mv old new |
mv -i pregunta antes de sobrescribir |
| borrar un archivo | rm file |
rm -i mientras aprendes |
| borrar una carpeta | rm -r "name" |
primero ls -d "name", mismas comillas |
| borrar una carpeta vacía | rmdir name |
falla sin daño si no está vacía |
| leer un manual | man cmd |
q para salir |
Medido: copiar frente a mover 10,000 archivos
¿Por qué mv de una carpeta enorme termina al instante mientras cp tarda segundos? Generamos 10,000 archivos de 200 a 8,000 bytes (59 MB en disco) con una semilla fija y medimos cp -R, mv y rm -r cinco veces cada uno en el mismo volumen APFS:
#!/bin/zsh -f
# bench.zsh WORKDIR - cp -R vs mv vs rm -r on 10,000 small files
zmodload zsh/datetime
cd "${1:?work dir}" || exit 1
rm -rf src copy moved
python3 - <<'PY'
import os, random
rng = random.Random(42)
for i in range(10000):
d = f"src/d{i % 100:02d}"
os.makedirs(d, exist_ok=True)
with open(f"{d}/f{i:05d}.txt", "w") as f:
f.write("x" * rng.randint(200, 8000))
PY
t() { local s=$EPOCHREALTIME; "$@"; printf '%.1f\n' $(( (EPOCHREALTIME - s) * 1000 )); }
for r in 1 2 3 4 5; do
sync
a=$(t cp -R src copy)
b=$(t mv copy moved)
c=$(t rm -r moved)
print "run $r: cp -R ${a} ms | mv ${b} ms | rm -r ${c} ms"
done
| Operación (10,000 archivos, 59 MB) | Mediana de 5 | Rango |
|---|---|---|
cp -R src copy |
5,692 ms | 3,749–6,708 ms |
cp -cR src clone (clon APFS) |
1,885 ms | 1,746–2,003 ms |
rm -r |
953 ms | 776–1,149 ms |
mv copy moved |
2.8 ms | 2.5–3.2 ms |
mv dentro del mismo volumen no toca los datos; cambia una sola entrada de directorio, así que tardó menos de 3 ms con 10,000 archivos. cp -R tiene que crear 10,000 archivos nuevos y escribir 59 MB. cp -c de macOS usa clonefile(2), que comparte los bloques de datos hasta que una de las copias cambia, así que es unas tres veces más rápido, pero igual crea cada entrada de archivo. Mover a otro disco (una memoria USB, un volumen distinto) es una copia real seguida de un borrado, así que cuesta al menos lo mismo que cp. Los tiempos de cp -R variaron mucho porque había otros trabajos corriendo en la misma máquina; el orden de los cuatro resultados nunca cambió.
Límites honestos y notas de versión
- Comprobado solo en macOS 26.6 con zsh 5.9 y bash 3.2.57. Los textos de error son los de las herramientas BSD de esta versión; Linux (GNU coreutils) usa otra redacción, por ejemplo
cannot remove 'backup': Is a directory(no ejecutado aquí). --helpfunciona con GNU coreutils en Linux (no ejecutado aquí). En macOS, apóyate enman.- El comportamiento de
interactive_commentsse comprobó con el/etc/zshrcde fábrica de macOS 26.6. La computadora de tu empresa puede traer un.zshrcque ya lo active. - La opción
cp -ces propia de macOS; solo la comprobamos en esta versión. - La medición es de una sola máquina, un solo volumen APFS y 5 repeticiones, con otros trabajos en marcha. Toma la proporción (aquí mv es unas 2,000 veces más rápido) como la lección, no los milisegundos exactos.
Ejercicios
- Dentro de
~/demo, crea la carpetatrip/2026 photosy, adentro, un archivo vacíoday 1.txt; luego lista todo lo que hay bajotrip. - Estás en
~/demo/projects/app. ¿A qué carpeta te llevacd ../../notes, y qué error obtienes si no existe? - Tienes que borrar una carpeta llamada
Old Files. Escribe los dos comandos que deberías ejecutar, en orden.
Respuestas
- Pon los nombres entre comillas (
touchcrea un archivo vacío yls -Rlista de forma recursiva):
~/demo % mkdir -p "trip/2026 photos"
~/demo % touch "trip/2026 photos/day 1.txt"
~/demo % ls -R trip
2026 photos
trip/2026 photos:
day 1.txt
- El primer
..sube aprojects, el segundo..sube a~/demoy luego entra anotes: terminas en~/demo/notes. Si no existe, zsh imprimecd: no such file or directory: ../../notesy te quedas donde estabas. - Primero comprueba y luego borra con exactamente el mismo nombre entre comillas:
~/demo % ls -d "Old Files"
Old Files
~/demo % rm -r "Old Files"
Siguiente: Clase 2: pipes, redirección y herramientas de texto, donde la salida de un comando se vuelve la entrada del siguiente. Más adelante en la serie: find, xargs, sed y awk (en inglés) y variables, scripts y códigos de salida (en inglés). Vuelve a la ruta de aprendizaje.
Preguntas frecuentes
¿Por qué cd My Project falla si la carpeta existe?
La shell separa las palabras en los espacios antes de que cd se ejecute, así que cd recibe dos palabras, My y Project. zsh responde 'cd: string not in pwd: My' y bash 3.2 responde 'cd: My: No such file or directory'. Pon el nombre entre comillas (cd "My Project") o escapa el espacio (cd My\ Project).
¿rm manda los archivos a la papelera?
No. rm elimina el nombre de inmediato y desde la shell no hay forma de deshacerlo. rm -i pregunta antes de cada archivo; para carpetas, ejecuta primero ls -d con el nombre exacto entre comillas y solo después rm -r con ese mismo nombre entre comillas.
¿Por qué ls --help no funciona en Mac?
macOS trae las versiones BSD de ls, cp y mkdir, que no tienen --help. Imprimen 'unrecognized option' o 'illegal option -- -' más un resumen de uso de una línea. El manual completo es man ls; presiona q para salir.