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). type te 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:

Diagrama de árbol. La raíz / lleva a la carpeta personal, escrita ~, que contiene demo, que a su vez contiene notes y projects. notes contiene todo.txt. La carpeta actual está marcada como ~/demo/projects. Desde ahí, el mismo archivo todo.txt se puede escribir como la ruta absoluta /…/demo/notes/todo.txt, como ~/demo/notes/todo.txt o como la ruta relativa ../notes/todo.txt, donde .. significa un nivel más arriba.
Un archivo, tres formas de nombrarlo. Una ruta absoluta empieza en /, ~ es tu carpeta personal y una ruta relativa parte de donde pwd dice que estás.
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
Gráfico de barras de las medianas con 10,000 archivos: cp -R 5,692 ms, cp -cR con clones APFS 1,885 ms, rm -r 953 ms y mv 2.8 ms.
Copiar frente a mover 10,000 archivos pequeños (59 MB) en el mismo volumen APFS, mediana de 5 ejecuciones, Mac con Apple Silicon (M1 Pro). mv solo renombra, así que tarda unos 3 ms.
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í).
  • --help funciona con GNU coreutils en Linux (no ejecutado aquí). En macOS, apóyate en man.
  • El comportamiento de interactive_comments se comprobó con el /etc/zshrc de fábrica de macOS 26.6. La computadora de tu empresa puede traer un .zshrc que ya lo active.
  • La opción cp -c es 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

  1. Dentro de ~/demo, crea la carpeta trip/2026 photos y, adentro, un archivo vacío day 1.txt; luego lista todo lo que hay bajo trip.
  2. Estás en ~/demo/projects/app. ¿A qué carpeta te lleva cd ../../notes, y qué error obtienes si no existe?
  3. Tienes que borrar una carpeta llamada Old Files. Escribe los dos comandos que deberías ejecutar, en orden.

Respuestas

  1. Pon los nombres entre comillas (touch crea un archivo vacío y ls -R lista 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
  1. El primer .. sube a projects, el segundo .. sube a ~/demo y luego entra a notes: terminas en ~/demo/notes. Si no existe, zsh imprime cd: no such file or directory: ../../notes y te quedas donde estabas.
  2. 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.

  • #shell
  • #terminal
  • #zsh
  • #macos
  • #línea de comandos
  • #principiante

t.laboratory

A technical blog that records real problems from the apps, servers and services we build and run — and the code that fixed them.

Acerca de · Apps

↑