En el Módulo 1 dibujaste el mapa: sabes qué es /etc, qué distingue /opt de /srv y por qué /var contiene lo que crece. Pero conocer un mapa y recorrer el terreno son cosas distintas. Esta lección es el recorrido.

Moverse por el sistema de archivos parece trivial —cd para ir, ls para mirar— y sin embargo es donde se pierde más tiempo a lo largo de una carrera. La diferencia entre alguien que navega con fluidez y alguien que no está en detalles concretos: saber volver al directorio anterior con dos teclas, leer la salida de ls -l de un vistazo, entender qué te dice exactamente cada marca de tiempo de un archivo, y no confundir «esto ocupa 4 KB» con «esto declara 18 bytes».

Un aviso antes de empezar: hasta el final de esta lección no vas a modificar nada. Todos los comandos que verás son de solo lectura. Es deliberado: primero se aprende a mirar, y en la lección siguiente se aprende a tocar.

Contenido

  1. pwd y el directorio de trabajo
  2. cd en todas sus formas
  3. Rutas absolutas y relativas en la práctica
  4. . y ..: entradas reales del directorio
  5. ls a fondo
  6. Leer ls -l columna a columna
  7. tree: ver la estructura de un vistazo
  8. stat y las tres marcas de tiempo
  9. file: qué es un archivo de verdad
  10. du y df: cuánto ocupa y cuánto queda
  11. No perderse nunca: hábitos de orientación
  12. Práctica guiada: recorrido por el árbol de Tramontana

  1. pwd y el directorio de trabajo

Cada proceso del sistema tiene un directorio de trabajo actual (current working directory, cwd): el punto del árbol desde el que interpreta las rutas relativas. Tu shell es un proceso y también tiene el suyo.

operador@srv-tramontana:~$ pwd
/home/operador

pwd (print working directory) responde siempre con una ruta absoluta, desde /.

Al iniciar sesión, tu directorio de trabajo es tu directorio personal, que en srv-tramontana es /home/operador. Por eso el prompt muestra ~: es la abreviatura del home.

pwd tiene dos opciones que solo cobran sentido cuando hay enlaces simbólicos por medio (lección 02-06):

Opción Comportamiento
-L (por defecto) Muestra la ruta lógica, tal como llegaste, con los enlaces sin resolver
-P Muestra la ruta física real, resolviendo todos los enlaces
operador@srv-tramontana:/opt/tramontana/app$ pwd
/opt/tramontana/app
operador@srv-tramontana:/opt/tramontana/app$ pwd -P
/opt/tramontana/releases/2026-08-18

Esa diferencia será importante cuando Tramontana adopte el patrón de despliegue con enlaces. De momento, quédate con que pwd -P te dice dónde estás de verdad.

  1. cd en todas sus formas

cd (change directory) cambia el directorio de trabajo. Es un builtin, y en la lección 02-01 viste por qué tiene que serlo.

Forma Qué hace
cd /ruta/absoluta Va a esa ruta, independientemente de dónde estés
cd subdirectorio Baja a un hijo del directorio actual
cd .. Sube al directorio padre
cd ../.. Sube dos niveles
cd (sin argumentos) Va a tu home
cd ~ Lo mismo, explícito
cd ~operador Al home de ese usuario
cd - Vuelve al directorio anterior
cd / A la raíz

Recorrido completo:

operador@srv-tramontana:~$ pwd
/home/operador

operador@srv-tramontana:~$ cd /var/log/tramontana
operador@srv-tramontana:/var/log/tramontana$ pwd
/var/log/tramontana

operador@srv-tramontana:/var/log/tramontana$ cd ..
operador@srv-tramontana:/var/log$ pwd
/var/log

operador@srv-tramontana:/var/log$ cd
operador@srv-tramontana:~$ pwd
/home/operador

Fíjate en cómo el prompt refleja el directorio actual. Es tu instrumento de orientación permanente y no cuesta nada mirarlo.

Las dos formas que más tiempo ahorran, y que mucha gente no conoce:

cd - alterna entre los dos últimos directorios, como el botón «atrás». Al usarlo, Bash imprime a dónde ha ido:

operador@srv-tramontana:~$ cd /etc/tramontana
operador@srv-tramontana:/etc/tramontana$ cd /var/log/tramontana
operador@srv-tramontana:/var/log/tramontana$ cd -
/etc/tramontana
operador@srv-tramontana:/etc/tramontana$ cd -
/var/log/tramontana

Es perfecto cuando estás comparando la configuración con los logs: dos teclas para saltar de un lado a otro.

~usuario es la ruta del home de otro usuario, resuelta por el shell:

operador@srv-tramontana:~$ echo ~
/home/operador
operador@srv-tramontana:~$ echo ~alumno
/home/alumno
operador@srv-tramontana:~$ echo ~root
/root

Ojo con ~root: es /root, no /home/root. La cuenta de administración tiene su home fuera de /home precisamente para que siga siendo accesible aunque /home esté en una partición que no se ha montado, algo que importa en la recuperación del sistema (lección 07-01).

Un comportamiento a tener en cuenta: si cd falla, no te mueves.

operador@srv-tramontana:~$ cd /etc/tramontanas
-bash: cd: /etc/tramontanas: No existe el fichero o el directorio
operador@srv-tramontana:~$ pwd
/home/operador

El prompt no cambió y pwd lo confirma. Este es el detalle que hacía peligroso el ; de la lección anterior: cd falla, pero el comando siguiente se ejecuta igual, en el sitio equivocado.

  1. Rutas absolutas y relativas en la práctica

La definición la viste en el Módulo 1. Aquí la vas a usar.

  • Absoluta: empieza por /. Significa lo mismo desde cualquier sitio.
  • Relativa: no empieza por /. Se interpreta desde el directorio actual.

El árbol de Tramontana que vas a usar como referencia:

/
├── etc/
│   └── tramontana/
│       └── app.conf
├── opt/
│   └── tramontana/
│       └── app/
│           ├── ejecutable
│           ├── plantillas/
│           └── version.txt
├── srv/
│   └── tramontana/
│       └── backups/
├── var/
│   └── log/
│       └── tramontana/
│           ├── acceso.log
│           └── errores.log
└── home/
    └── operador/
        ├── scripts/
        └── datos/
            ├── reservas.csv
            └── casas.txt

Ejercicios de traducción. Estás en /var/log/tramontana. ¿Cómo llegas a cada destino de las dos maneras?

Destino Ruta absoluta Ruta relativa
errores.log (mismo dir.) /var/log/tramontana/errores.log errores.log o ./errores.log
El directorio /var/log /var/log ..
/etc/tramontana/app.conf /etc/tramontana/app.conf ../../../etc/tramontana/app.conf
/opt/tramontana/app /opt/tramontana/app ../../../opt/tramontana/app
Tu home /home/operador ~ o ../../../home/operador

Comprobación práctica de la tercera fila:

operador@srv-tramontana:/var/log/tramontana$ ls ../../../etc/tramontana/
app.conf

Tres .. porque hay que subir de tramontana a log, de log a var, y de var a /. Cuenta los niveles del prompt y te salen solos.

Cuándo usar cada una:

Contexto Usa Por qué
Trabajo interactivo, cerca de donde estás Relativa Más corta, menos que teclear
Scripts (Módulo 4) Absoluta, siempre El script puede ejecutarse desde cualquier directorio
Tareas de cron (03-07) Absoluta, siempre Cron arranca en un directorio que no controlas
Configuración de servicios Absoluta El servicio no comparte tu directorio de trabajo
Documentar un procedimiento Absoluta Quien lo lea no sabe dónde estabas

Regla mnemotécnica: relativa para tus dedos, absoluta para las máquinas.

  1. . y ..: entradas reales del directorio

. es el directorio actual y .. es el padre. Pero no son un truco del shell: son entradas reales dentro de cada directorio, escritas en disco.

operador@srv-tramontana:~$ ls -la /home/operador/datos
total 16
drwxr-xr-x 2 operador operador 4096 ago 18 08:11 .
drwxr-x--- 5 operador operador 4096 ago 18 08:11 ..
-rw-r--r-- 1 operador operador  418 ago 17 19:40 casas.txt
-rw-r--r-- 1 operador operador 1204 ago 18 07:55 reservas.csv

Las dos primeras líneas son entradas de verdad, con sus permisos, su propietario y su fecha. Comprobación definitiva:

operador@srv-tramontana:~$ ls -ldi /home/operador/datos /home/operador/datos/.
 262148 drwxr-xr-x 2 operador operador 4096 ago 18 08:11 /home/operador/datos
 262148 drwxr-xr-x 2 operador operador 4096 ago 18 08:11 /home/operador/datos/.

El mismo número, 262148. Ese número es el inodo, y que coincida demuestra que . y el directorio son literalmente el mismo objeto. Los inodos son el tema de la lección 02-06; guarda este dato.

Dos consecuencias prácticas:

./ es obligatorio para ejecutar un programa del directorio actual. Como viste en 02-01, el directorio actual no está en el PATH:

operador@srv-tramontana:~/scripts$ informe.sh
-bash: informe.sh: orden no encontrada
operador@srv-tramontana:~/scripts$ ./informe.sh
Generando informe de reservas...

./ protege frente a nombres que empiezan por guion, como viste con el separador --. rm ./-informe.txt funciona siempre.

Un detalle sobre el directorio raíz: en /, la entrada .. apunta a sí misma. cd /.. te deja en /. El árbol termina ahí.

  1. ls a fondo

ls es el comando que más veces ejecutarás en tu vida. Merece la pena conocerlo bien.

Opción Qué hace
-l Formato largo: permisos, propietario, tamaño, fecha
-a Muestra todo, incluidos los ocultos, . y ..
-A Como -a pero sin . ni .. (casi siempre más útil)
-h Tamaños legibles (K, M, G). Requiere -l
-t Ordena por fecha de modificación, más reciente primero
-S Ordena por tamaño, mayor primero
-r Invierte el orden
-R Recursivo: entra en los subdirectorios
-d Muestra el directorio en sí, no su contenido
-i Muestra el número de inodo
-1 Un elemento por línea (útil con tuberías)
-F Añade un símbolo según el tipo: / dir., * ejecutable, @ enlace
--color=auto Colorea por tipo (ya viene como alias en Ubuntu)

Sin opciones, ls es escueto porque el shell antiguo lo era:

operador@srv-tramontana:~$ ls
datos  scripts

Combinaciones que se usan de verdad:

# La más común: todo, largo, tamaños legibles
operador@srv-tramontana:~$ ls -lah /var/log/tramontana
total 32K
drwxr-x---  2 root      adm      4,0K ago 18 09:00 .
drwxrwxr-x 12 root      syslog   4,0K ago 18 00:00 ..
-rw-r-----  1 root      adm       18K ago 18 09:14 acceso.log
-rw-r-----  1 root      adm      6,2K ago 18 09:02 errores.log

# Lo último que ha cambiado, arriba del todo: para diagnosticar
operador@srv-tramontana:~$ ls -lt /etc/tramontana
total 4
-rw-r----- 1 root tramontana 512 ago 18 08:47 app.conf

# Lo último abajo: mejor cuando hay muchos archivos, porque queda junto al prompt
operador@srv-tramontana:~$ ls -ltr /var/log
...
-rw-r-----  1 syslog adm    124832 ago 18 09:15 syslog

# Los más grandes primero: para encontrar qué llena un disco
operador@srv-tramontana:~$ ls -lhS /var/log/tramontana
-rw-r----- 1 root adm  18K ago 18 09:14 acceso.log
-rw-r----- 1 root adm 6,2K ago 18 09:02 errores.log

ls -ltr merece un comentario: al ordenar de más antiguo a más reciente, lo último modificado queda justo encima del prompt, donde tienes la vista. En un directorio con doscientos archivos, eso es la diferencia entre ver la respuesta y tener que buscarla.

-d es la opción menos intuitiva y más necesaria. Sin ella, ls -l sobre un directorio lista su contenido; con ella, describe el directorio mismo:

operador@srv-tramontana:~$ ls -l /etc/tramontana
total 4
-rw-r----- 1 root tramontana 512 ago 18 08:47 app.conf

operador@srv-tramontana:~$ ls -ld /etc/tramontana
drwxr-x--- 2 root tramontana 4096 ago 18 08:30 /etc/tramontana

La primera te dice qué hay dentro; la segunda te dice quién puede entrar. Cuando llegues a los permisos en la lección 02-07, ls -ld será tu herramienta principal.

-R recorre el árbol entero. Úsalo con cuidado: ls -R / produce cientos de miles de líneas.

operador@srv-tramontana:~$ ls -R /opt/tramontana
/opt/tramontana:
app

/opt/tramontana/app:
ejecutable  plantillas  version.txt

/opt/tramontana/app/plantillas:
confirmacion.html  factura.html

  1. Leer ls -l columna a columna

Esta salida hay que saber leerla de un vistazo, porque contiene casi toda la información relevante de un archivo:

operador@srv-tramontana:~$ ls -l /var/log/tramontana/acceso.log
-rw-r----- 1 root adm 18432 ago 18 09:14 /var/log/tramontana/acceso.log

Desmontada:

Columna Valor Significado
1 (1er carácter) - Tipo: archivo regular. d directorio, l enlace, c/b dispositivo, s socket, p tubería
1 (resto) rw-r----- Permisos: tres grupos de tres. Lección 02-07
2 1 Número de enlaces duros. Lección 02-06
3 root Propietario
4 adm Grupo propietario
5 18432 Tamaño en bytes (con -h, en unidades legibles)
6 ago 18 09:14 Fecha de última modificación (mtime)
7 acceso.log Nombre

Un detalle de la sexta columna: ls muestra la hora si el archivo se modificó en los últimos seis meses, y el año si es más antiguo. Esa asimetría desconcierta la primera vez:

operador@srv-tramontana:~$ ls -l /etc/hostname /var/log/tramontana/acceso.log
-rw-r--r-- 1 root root    16 jun 12  2025 /etc/hostname
-rw-r----- 1 root adm  18432 ago 18 09:14 /var/log/tramontana/acceso.log

Si quieres fechas completas y sin ambigüedad:

operador@srv-tramontana:~$ ls -l --time-style=full-iso /var/log/tramontana/acceso.log
-rw-r----- 1 root adm 18432 2026-08-18 09:14:37.482910233 +0200 /var/log/tramontana/acceso.log

La segunda columna, el número de enlaces, tiene un comportamiento que sorprende: en los directorios nunca vale 1.

operador@srv-tramontana:~$ ls -ld /opt/tramontana/app
drwxr-xr-x 4 root root 4096 ago 18 08:30 /opt/tramontana/app

Vale 4 porque cuentan: la entrada app en /opt/tramontana, la entrada . dentro de app, y las entradas .. de sus dos subdirectorios. El número de enlaces de un directorio es 2 + el número de subdirectorios que contiene. Es un truco para contar subdirectorios sin entrar, y quedará completamente claro en la lección 02-06.

Y el tamaño de un directorio (4096) no es lo que contiene: es lo que ocupa la propia lista de nombres. Para saber lo que contiene está du, en el apartado 10.

  1. tree: ver la estructura de un vistazo

tree muestra la jerarquía dibujada. No viene instalado por defecto en Ubuntu Server:

operador@srv-tramontana:~$ tree
Orden «tree» no encontrada, pero se puede instalar con:
sudo apt install tree

operador@srv-tramontana:~$ sudo apt install -y tree

(La gestión de paquetes se estudia en la lección 05-03; aquí lo instalamos y seguimos.)

operador@srv-tramontana:~$ tree /opt/tramontana
/opt/tramontana
└── app
    ├── ejecutable
    ├── plantillas
    │   ├── confirmacion.html
    │   └── factura.html
    └── version.txt

3 directories, 4 files

Opciones imprescindibles:

Opción Qué hace
-L n Limita la profundidad a n niveles
-d Solo directorios
-a Incluye ocultos
-h Muestra tamaños legibles
-F Añade / a los directorios
--du Suma el tamaño de cada rama

-L es prácticamente obligatoria en directorios grandes:

operador@srv-tramontana:~$ tree -L 1 /
/
├── bin -> usr/bin
├── boot
├── dev
├── etc
├── home
├── lib -> usr/lib
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/sbin
├── srv
├── sys
├── tmp
├── usr
└── var

Ahí ves algo interesante: bin, lib y sbin aparecen con una flecha. Son enlaces simbólicos a directorios dentro de /usr, resultado de la reorganización /usr-merge que hicieron las distribuciones modernas. La lección 02-06 explica exactamente qué significa esa flecha.

Combinación muy útil para documentar la estructura de un proyecto:

operador@srv-tramontana:~$ tree -d -L 2 /var
/var
├── backups
├── cache
├── lib
├── log
│   ├── apt
│   └── tramontana
├── spool
└── tmp

  1. stat y las tres marcas de tiempo

ls -l da un resumen. stat da todo:

operador@srv-tramontana:~$ stat /home/operador/datos/reservas.csv
  Fichero: /home/operador/datos/reservas.csv
  Tamaño: 1204        Bloques: 8          Bloque E/S: 4096   fichero regular
Dispositivo: 8,2	Nodo-i: 262151      Enlaces: 1
Acceso: (0644/-rw-r--r--)  Uid: ( 1001/operador)   Gid: ( 1001/operador)
     Acceso: 2026-08-18 09:20:11.104283761 +0200
Modificación: 2026-08-18 07:55:02.882910233 +0200
      Cambio: 2026-08-18 07:55:02.882910233 +0200
    Creación: 2026-08-10 12:03:44.000000000 +0200

Lo que aporta sobre ls -l:

  • El número de inodo (262151) y el dispositivo donde vive.
  • Los permisos en octal y simbólico a la vez (0644/-rw-r--r--), muy útil para la lección 02-07.
  • Los UID y GID numéricos además de los nombres.
  • Los bloques realmente ocupados.
  • Y las marcas de tiempo con precisión de nanosegundos.

Las tres marcas clásicas se confunden constantemente. Esta tabla resuelve la confusión:

Marca Nombre Se actualiza cuando... No se actualiza cuando...
atime Acceso Se lee el contenido (cat, less) Solo miras sus metadatos con ls
mtime Modificación Cambia el contenido Cambian los permisos o el propietario
ctime Cambio de inodo Cambia el contenido o los metadatos Nunca lo puedes fijar tú a mano

El error más extendido es creer que ctime significa creation time. No es así: es change time, el momento en que cambió el inodo. Cambiar los permisos de un archivo actualiza su ctime pero no su mtime.

Demostración:

operador@srv-tramontana:~$ stat -c '%y  %z' datos/casas.txt
2026-08-17 19:40:10.000000000 +0200  2026-08-17 19:40:10.000000000 +0200

operador@srv-tramontana:~$ chmod 640 datos/casas.txt

operador@srv-tramontana:~$ stat -c '%y  %z' datos/casas.txt
2026-08-17 19:40:10.000000000 +0200  2026-08-18 09:31:55.771820102 +0200

El mtime (%y) no se movió: el contenido no cambió. El ctime (%z) sí: el inodo se modificó al cambiar los permisos. Esta distinción es la base de la detección de intrusiones (lección 06-04): un atacante puede falsificar el mtime, pero no el ctime.

La cuarta línea, Creación (birth time), es relativamente moderna. Existe en ext4 y otros sistemas de archivos actuales, pero no todas las herramientas la exponen y no se puede consultar de forma portable.

Un detalle sobre atime que conviene conocer: actualizarlo cada vez que se lee un archivo implica una escritura en disco por cada lectura, lo que sería un desastre de rendimiento. Por eso Linux monta los sistemas de archivos con la opción relatime, que solo actualiza atime si es más antiguo que mtime o si han pasado más de 24 horas. Consecuencia: el atime que ves es aproximado. No lo uses para auditoría precisa.

stat acepta formatos personalizados con -c:

operador@srv-tramontana:~$ stat -c '%n: %s bytes, permisos %a, dueño %U:%G' datos/*
datos/casas.txt: 418 bytes, permisos 640, dueño operador:operador
datos/reservas.csv: 1204 bytes, permisos 644, dueño operador:operador

Esa forma es la que usarás en los scripts del Módulo 4 para generar informes.

  1. file: qué es un archivo de verdad

En Windows, la extensión determina el tipo. En Linux la extensión es solo parte del nombre: no significa nada para el sistema. Lo que determina el tipo es el contenido, y quien lo interpreta es el programa que lo abre.

file examina los primeros bytes de un archivo y los compara con una base de datos de firmas conocidas (los números mágicos):

operador@srv-tramontana:~$ file /home/operador/datos/*
/home/operador/datos/casas.txt:    UTF-8 Unicode text
/home/operador/datos/reservas.csv: CSV text

operador@srv-tramontana:~$ file /opt/tramontana/app/ejecutable
/opt/tramontana/app/ejecutable: ELF 64-bit LSB pie executable, x86-64,
 dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, ...

operador@srv-tramontana:~$ file /etc/tramontana /dev/null /dev/sda
/etc/tramontana: directory
/dev/null:       character special (1/3)
/dev/sda:        block special (8/0)

Prueba definitiva de que la extensión no manda:

operador@srv-tramontana:~$ cp datos/casas.txt /tmp/casas.jpg
operador@srv-tramontana:~$ file /tmp/casas.jpg
/tmp/casas.jpg: UTF-8 Unicode text

Se llama .jpg y sigue siendo texto. file no se deja engañar por el nombre.

Casos en los que file te salva de un problema:

# ¿Con qué está comprimido este archivo que me han pasado?
operador@srv-tramontana:~$ file /srv/tramontana/backups/copia-2026-08-17
/srv/tramontana/backups/copia-2026-08-17: gzip compressed data, from Unix

# ¿Por qué el script falla con un error raro?
operador@srv-tramontana:~$ file scripts/informe.sh
scripts/informe.sh: Bourne-Again shell script, ASCII text executable,
 with CRLF line terminators

Ese último ejemplo es un clásico: with CRLF line terminators significa que el archivo tiene finales de línea de Windows. Bash intenta ejecutar /bin/bash\r y falla con un mensaje incomprensible. file da el diagnóstico en un segundo.

Opciones útiles:

Opción Qué hace
-b Solo el tipo, sin el nombre del archivo
-i Devuelve el tipo MIME (text/plain, application/gzip)
-L Sigue los enlaces simbólicos
operador@srv-tramontana:~$ file -bi datos/reservas.csv
text/csv; charset=us-ascii

Hábito profesional: pasa file a todo archivo desconocido antes de abrirlo. En la lección 02-05 verás por qué hacer cat de un binario destroza tu terminal; file es la comprobación que lo evita.

  1. du y df: cuánto ocupa y cuánto queda

Dos comandos que se confunden y responden a preguntas distintas:

  • df (disk free): cuánto espacio queda en los sistemas de archivos montados. Pregunta al sistema de archivos.
  • du (disk usage): cuánto ocupa un directorio concreto. Recorre y suma.
operador@srv-tramontana:~$ df -h
S.ficheros     Tamaño Usados  Disp Uso% Montado en
tmpfs            389M   1,4M  388M   1% /run
/dev/sda2         23G   6,7G   15G  30% /
tmpfs            1,9G      0  1,9G   0% /dev/shm
tmpfs            5,0M      0  5,0M   0% /run/lock
/dev/sda1        1,1G   6,4M  1,1G   1% /boot/efi

Ahí ves el disco de 23 GB al 30 % que conoces de la instalación. Las líneas tmpfs son sistemas de archivos en memoria RAM, no en disco: por eso /run y /dev/shm desaparecen al reiniciar.

Opción imprescindible que casi nadie usa:

operador@srv-tramontana:~$ df -hi /
S.ficheros     Nodos NUsados NLibres NUso% Montado en
/dev/sda2       1,5M    112K    1,4M    8% /

-i muestra los inodos, no los bytes. Un disco puede tener espacio libre y aun así dar «No queda espacio en el dispositivo» si se han agotado los inodos, típicamente por millones de archivos diminutos. Es una incidencia que desconcierta a quien no sabe que existe, y df -hi es el diagnóstico en un segundo.

du responde a la pregunta contraria:

operador@srv-tramontana:~$ sudo du -sh /var/log/tramontana
26K	/var/log/tramontana
Opción Qué hace
-s Resumen: solo el total, sin desglosar
-h Legible
-c Añade una línea de total al final
-d n Baja n niveles en el desglose
--apparent-size Tamaño declarado, no el ocupado en disco
-x No cruza a otros sistemas de archivos

Sin -s, du desglosa cada subdirectorio, lo que en / produce una avalancha. Con -d 1 obtienes el desglose de un nivel, que es lo que quieres para buscar culpables:

operador@srv-tramontana:~$ sudo du -h -d 1 /var/log
4,0K	/var/log/apt
26K	/var/log/tramontana
8,0K	/var/log/private
1,3M	/var/log

La última línea es el total de /var/log, incluidos los archivos sueltos que no están en ningún subdirectorio.

La diferencia entre tamaño declarado y espacio ocupado explica una discrepancia que confunde:

operador@srv-tramontana:~$ echo "hola" > /tmp/prueba.txt
operador@srv-tramontana:~$ ls -l /tmp/prueba.txt
-rw-rw-r-- 1 operador operador 5 ago 18 09:45 /tmp/prueba.txt
operador@srv-tramontana:~$ du -h /tmp/prueba.txt
4,0K	/tmp/prueba.txt
operador@srv-tramontana:~$ du -h --apparent-size /tmp/prueba.txt
5	/tmp/prueba.txt

El archivo declara 5 bytes, pero ocupa 4 KB porque el sistema de archivos asigna espacio en bloques y el bloque mínimo de ext4 es de 4 KB. Un directorio con cien mil archivos de 5 bytes ocupa 400 MB reales.

Por eso du (que mide lo ocupado) y df (que mide lo libre en el dispositivo) pueden no cuadrar. Otra causa clásica de descuadre: un archivo borrado que sigue abierto por un proceso. Desaparece del árbol, así que du no lo ve, pero el espacio no se libera hasta que el proceso lo cierra, así que df sí lo cuenta. Es el motivo por el que borrar un log enorme sin reiniciar el servicio no libera espacio, y lo retomarás en la lección 05-07.

  1. No perderse nunca: hábitos de orientación

Tres costumbres que evitan el 90 % de los sustos:

1. Lee el prompt antes de cada comando destructivo. El prompt de Ubuntu ya muestra el directorio actual. No cuesta nada mirarlo, y en el instante anterior a un rm es lo que separa borrar lo correcto de borrar lo otro.

2. pwd como reflejo. Tras cualquier cd encadenado, tras volver de una pausa, tras conectarte por SSH a otra máquina. Es gratis.

3. Antes de actuar, mira. El patrón que ya viste en 02-01 y que se repetirá todo el curso:

operador@srv-tramontana:~$ ls -la /srv/tramontana/backups/temporales   # 1. mirar
operador@srv-tramontana:~$ pwd                                          # 2. confirmar dónde estoy
operador@srv-tramontana:~$ cd /srv/tramontana/backups/temporales && ... # 3. actuar con &&

Un cuarto hábito, para más adelante: cuando trabajes en varios servidores a la vez, personaliza el prompt para que muestre el nombre de la máquina en color distinto. Es la forma de no ejecutar en producción lo que ibas a ejecutar en pruebas. Se hace con la variable PS1 (lección 03-01).

  1. Práctica guiada: recorrido por el árbol de Tramontana

Vamos a recorrer entero el despliegue de Tramontana Reservas, describiendo cada pieza. Este recorrido es el que harías al recibir un servidor que no conoces.

Punto de partida y visión general:

operador@srv-tramontana:~$ pwd
/home/operador
operador@srv-tramontana:~$ df -h /
S.ficheros     Tamaño Usados  Disp Uso% Montado en
/dev/sda2         23G   6,7G   15G  30% /

Un solo sistema de archivos para todo el árbol, al 30 %. Bien de espacio, y también significa que cualquier cosa que crezca sin control afecta a todo el sistema.

La aplicación:

operador@srv-tramontana:~$ tree -L 2 /opt/tramontana
/opt/tramontana
└── app
    ├── ejecutable
    ├── plantillas
    └── version.txt

operador@srv-tramontana:~$ ls -ld /opt/tramontana/app
drwxr-xr-x 4 root root 4096 ago 18 08:30 /opt/tramontana/app

operador@srv-tramontana:~$ cat /opt/tramontana/app/version.txt
Tramontana Reservas 3.2.1

operador@srv-tramontana:~$ file /opt/tramontana/app/ejecutable
/opt/tramontana/app/ejecutable: ELF 64-bit LSB pie executable, x86-64

operador@srv-tramontana:~$ du -sh /opt/tramontana/app
48M	/opt/tramontana/app

Diagnóstico: software de terceros en /opt según el FHS, propiedad de root (los usuarios no pueden modificar el código: correcto), 48 MB, un binario compilado y sus plantillas. Datos estáticos: no cambian salvo en un despliegue.

La configuración:

operador@srv-tramontana:~$ ls -l /etc/tramontana/
total 4
-rw-r----- 1 root tramontana 512 ago 18 08:47 app.conf

operador@srv-tramontana:~$ stat -c 'permisos %a, dueño %U:%G, modificado %y' /etc/tramontana/app.conf
permisos 640, dueño root:tramontana, modificado 2026-08-18 08:47:12.338291044 +0200

Dos cosas relevantes. La primera: permisos 640, es decir, nadie que no sea root o del grupo tramontana puede leerla, lo cual es correcto porque contiene credenciales. La segunda: el grupo tramontana aparece aquí, y todavía no lo hemos creado formalmente; eso se hará en la lección 05-01. El significado exacto del 640 es la lección 02-07.

Fíjate también en el mtime: se modificó esta mañana a las 8:47. En un servidor que no debería cambiar, una configuración modificada recientemente es lo primero que se investiga ante una incidencia.

Los logs:

operador@srv-tramontana:~$ sudo ls -lh /var/log/tramontana/
total 25K
-rw-r----- 1 root adm  18K ago 18 09:14 acceso.log
-rw-r----- 1 root adm 6,2K ago 18 09:02 errores.log

operador@srv-tramontana:~$ sudo du -sh /var/log/tramontana
26K	/var/log/tramontana

operador@srv-tramontana:~$ sudo file /var/log/tramontana/acceso.log
/var/log/tramontana/acceso.log: ASCII text

Datos variables: crecen con el uso. 26 KB hoy no es nada, pero un log de acceso en producción crece de forma lineal con el tráfico, y ese es exactamente el escenario que justificaba ponerlo en /var. Que sea ASCII text importa: significa que todas las herramientas de procesamiento de texto del Módulo 3 funcionarán sobre él.

Las copias y los datos de trabajo:

operador@srv-tramontana:~$ ls -ld /srv/tramontana/backups
drwxr-x--- 2 root root 4096 ago 18 08:30 /srv/tramontana/backups

operador@srv-tramontana:~$ ls -lh ~/datos/
total 8,0K
-rw-r----- 1 operador operador  418 ago 17 19:40 casas.txt
-rw-r--r-- 1 operador operador 1,2K ago 18 07:55 reservas.csv

operador@srv-tramontana:~$ head -n 3 ~/datos/reservas.csv
id;fecha;casa;huesped;noches;importe
1001;2026-07-03;mas-figueres;Nuria Prat;4;620.00
1002;2026-07-05;can-ventos;Oriol Sala;2;280.00

Los datos de trabajo están en tu home, separados de la aplicación. reservas.csv usa punto y coma como separador, un detalle que será importante al procesarlo en la lección 03-05.

Resumen del recorrido, en el formato de informe que Marta espera:

Ruta Contenido Naturaleza Tamaño Propietario
/opt/tramontana/app Binario y plantillas Estático 48 M root:root
/etc/tramontana/app.conf Configuración con credenciales Estático, sensible 512 B root:tramontana
/var/log/tramontana/ Registros de acceso y error Variable, crece 26 K root:adm
/srv/tramontana/backups Copias de seguridad Variable, crece a saltos 0 root:root
/home/operador/datos Datos de trabajo Variable 8 K operador:operador

Con cinco comandos —df, tree, ls -l, stat, du— has caracterizado un servidor completo sin tocar nada. Ese es el reconocimiento inicial que se hace al heredar un sistema.

Errores Comunes y Consejos

Confundir .. con .. cd . no hace nada, cd .. sube. Un carácter, mucha diferencia.

Usar rutas relativas en scripts. Funciona mientras lo ejecutas a mano desde el directorio adecuado, y falla el día que lo lanza cron desde /. Absolutas siempre en scripts.

Creer que el tamaño de un directorio en ls -l es lo que contiene. No: son 4096 bytes de índice. Usa du -sh.

Confundir du con df. Si preguntas «cuánto queda en el disco», es df. Si preguntas «qué está ocupando tanto», es du.

Creer que ctime es la fecha de creación. Es change time. La creación real, cuando está disponible, la muestra stat como «Creación».

Fiarse de la extensión. Un .txt puede ser un binario y un archivo sin extensión puede ser un ejecutable. file es la respuesta.

Consejo: cd - y pushd/popd. cd - alterna entre dos. Si necesitas una pila de directorios, pushd y popd la implementan; son builtins y su documentación está en help pushd.

Consejo: ls -ltr en directorios con muchos archivos. Lo más reciente queda pegado al prompt.

Consejo: ls -ld es la opción que más se olvida. Cada vez que quieras saber algo del directorio y no de su contenido, es -d.

Consejo: df -hi cuando «no queda espacio» pero df -h dice que sí. Se han agotado los inodos.

Ejercicios

Ejercicio 1: traducción de rutas

Sin ejecutar nada, partiendo del árbol de Tramontana del apartado 3 y estando en /opt/tramontana/app/plantillas:

  1. Ruta relativa a /opt/tramontana/app/version.txt.
  2. Ruta relativa a /etc/tramontana/app.conf.
  3. ¿Qué directorio es ../../../../var/log?
  4. ¿Qué hace cd ../.. desde ahí, y cuál es el pwd resultante?

Después comprueba tus respuestas en el servidor.

Ejercicio 2: caracterizar un directorio desconocido

Marta te pide que revises el directorio /var/log de srv-tramontana porque «el disco parece que va llenándose». Sin borrar nada, averigua y presenta:

  1. Cuánto espacio libre queda en la partición raíz y qué porcentaje se usa.
  2. Cuánto ocupa /var/log en total.
  3. Qué tres subdirectorios de /var/log ocupan más.
  4. Cuál es el archivo modificado más recientemente dentro de /var/log/tramontana y a qué hora.
  5. Si ese archivo es texto o binario.

Ejercicio 3: las marcas de tiempo

En tu home, con un archivo de prueba:

  1. Crea /tmp/marcas.txt con algo de contenido y anota sus tres marcas de tiempo.
  2. Léelo con cat. ¿Cuál cambió?
  3. Cambia sus permisos con chmod 600. ¿Cuál cambió ahora?
  4. Añádele contenido. ¿Cuáles cambiaron?
  5. Explica por qué un atacante que quiere ocultar que ha modificado un archivo del sistema puede falsificar el mtime pero le resulta mucho más difícil falsificar el ctime.

Soluciones

Solución 1

1. ../version.txt — subes de plantillas a app y ahí está el archivo.

operador@srv-tramontana:/opt/tramontana/app/plantillas$ cat ../version.txt
Tramontana Reservas 3.2.1

2. ../../../etc/tramontana/app.conf. Cuenta los niveles: de plantillas a app (uno), a tramontana (dos), a opt (tres)... y desde opt hay que subir uno más hasta /. Son cuatro: ../../../../etc/tramontana/app.conf.

Comprobémoslo, que es justo el tipo de error que se comete:

operador@srv-tramontana:/opt/tramontana/app/plantillas$ ls ../../../etc/tramontana/
ls: no se puede acceder a '../../../etc/tramontana/': No existe el fichero o el directorio

operador@srv-tramontana:/opt/tramontana/app/plantillas$ ls ../../../../etc/tramontana/
app.conf

La ruta absoluta actual tiene cuatro componentes (opt, tramontana, app, plantillas), así que hacen falta cuatro .. para llegar a la raíz. Esta es exactamente la razón por la que las rutas absolutas son mejores en cuanto la distancia pasa de un par de niveles: /etc/tramontana/app.conf no admite este error.

3. ../../../../var/log es /var/log, por el mismo cálculo.

4. cd ../.. sube dos niveles: de plantillas a app, y de app a tramontana.

operador@srv-tramontana:/opt/tramontana/app/plantillas$ cd ../..
operador@srv-tramontana:/opt/tramontana$ pwd
/opt/tramontana

Solución 2

# 1. Espacio en la raíz
operador@srv-tramontana:~$ df -h /
S.ficheros     Tamaño Usados  Disp Uso% Montado en
/dev/sda2         23G   6,7G   15G  30% /

15 GB libres, 30 % usado. Sin problema por ahora.

# 2. Total de /var/log
operador@srv-tramontana:~$ sudo du -sh /var/log
1,3M	/var/log

1,3 MB sobre 23 GB: /var/log no es la causa de que el disco se llene. Este es el dato que cierra la pregunta de Marta.

# 3. Los tres subdirectorios más grandes
operador@srv-tramontana:~$ sudo du -h -d 1 /var/log | sort -h | tail -n 4
8,0K	/var/log/private
26K	/var/log/tramontana
912K	/var/log/journal
1,3M	/var/log

(El | sort -h | tail es una tubería; se explica a fondo en el Módulo 3. Puedes obtener lo mismo leyendo la salida de du -h -d 1 /var/log a ojo.)

El mayor consumidor es journal, el registro de systemd, con 912 KB. Es normal y tiene límite de tamaño configurable (lección 05-06).

# 4. El más reciente en /var/log/tramontana
operador@srv-tramontana:~$ sudo ls -lt --time-style=long-iso /var/log/tramontana
total 25
-rw-r----- 1 root adm 18432 2026-08-18 09:14 acceso.log
-rw-r----- 1 root adm  6348 2026-08-18 09:02 errores.log

acceso.log, modificado a las 09:14. -t ordena por fecha descendente, así que el primero es el más reciente.

# 5. Tipo de archivo
operador@srv-tramontana:~$ sudo file /var/log/tramontana/acceso.log
/var/log/tramontana/acceso.log: ASCII text

Informe para Marta: el disco raíz está al 30 % con 15 GB libres. /var/log ocupa 1,3 MB en total, así que no es lo que está llenando el disco; conviene mirar en otro sitio. Dentro de los registros, el mayor consumidor es el diario del sistema (912 KB) y los logs de la aplicación suman 26 KB. El registro de acceso se actualizó por última vez a las 09:14 de hoy, lo que confirma que la aplicación está funcionando y escribiendo con normalidad.

Solución 3

operador@srv-tramontana:~$ echo "linea inicial" > /tmp/marcas.txt
operador@srv-tramontana:~$ stat -c 'atime=%x%nmtime=%y%nctime=%z' /tmp/marcas.txt
atime=2026-08-18 10:02:14.118293011 +0200
mtime=2026-08-18 10:02:14.118293011 +0200
ctime=2026-08-18 10:02:14.118293011 +0200

Al crearlo, las tres coinciden.

operador@srv-tramontana:~$ cat /tmp/marcas.txt
linea inicial
operador@srv-tramontana:~$ stat -c 'atime=%x%nmtime=%y%nctime=%z' /tmp/marcas.txt
atime=2026-08-18 10:03:41.554820119 +0200
mtime=2026-08-18 10:02:14.118293011 +0200
ctime=2026-08-18 10:02:14.118293011 +0200

Solo cambió atime: has leído el contenido, no lo has modificado. (Si no ves el cambio, es por relatime: si atime ya era más reciente que mtime y no han pasado 24 horas, el kernel no lo actualiza. Es el comportamiento normal y esperado.)

operador@srv-tramontana:~$ chmod 600 /tmp/marcas.txt
operador@srv-tramontana:~$ stat -c 'atime=%x%nmtime=%y%nctime=%z' /tmp/marcas.txt
atime=2026-08-18 10:03:41.554820119 +0200
mtime=2026-08-18 10:02:14.118293011 +0200
ctime=2026-08-18 10:05:02.771820102 +0200

Solo cambió ctime: has modificado el inodo (los permisos viven ahí), no el contenido ni lo has leído. Esta es la demostración de que ctime no es creation time.

operador@srv-tramontana:~$ echo "segunda linea" >> /tmp/marcas.txt
operador@srv-tramontana:~$ stat -c 'atime=%x%nmtime=%y%nctime=%z' /tmp/marcas.txt
atime=2026-08-18 10:03:41.554820119 +0200
mtime=2026-08-18 10:06:33.201938477 +0200
ctime=2026-08-18 10:06:33.201938477 +0200

Cambiaron mtime y ctime. El contenido cambió (mtime) y, al cambiar el contenido, también cambió el tamaño registrado en el inodo (ctime). No cambió atime porque escribir no es leer.

Punto 5: por qué el ctime es difícil de falsificar. El comando touch permite fijar atime y mtime al valor que quieras (touch -t, lección 02-04). Un atacante que modifica /etc/tramontana/app.conf puede dejar el mtime exactamente como estaba y el archivo parecerá intacto en ls -l.

Pero el ctime no se puede fijar. No hay ninguna llamada al sistema que permita escribir un valor arbitrario en él: el kernel lo actualiza automáticamente cada vez que el inodo cambia, incluido el cambio que provoca el propio touch al falsificar el mtime. Falsificar el ctime exige acceso directo al dispositivo de bloques por debajo del sistema de archivos, o cambiar el reloj del sistema, y ambas cosas dejan otros rastros.

De ahí la práctica forense: ante la sospecha de una intrusión, se comparan mtime y ctime. Un archivo cuyo ctime es muy posterior a su mtime ha sido tocado de una forma que merece explicación. Es uno de los indicadores que usan las herramientas de la lección 06-04.

Conclusión

Ya no navegas a tientas por el árbol del Módulo 1: lo recorres con instrumentos.

  • pwd te dice dónde estás, y pwd -P dónde estás de verdad cuando hay enlaces por medio.
  • cd tiene más formas de las que parecía: cd - para alternar, cd a secas para volver a casa, ~usuario para el home ajeno. Y si falla, no te mueves, que es justo lo que hacía peligroso el ;.
  • Sabes traducir entre rutas absolutas y relativas contando niveles, y tienes el criterio: relativas para tus dedos, absolutas para scripts y cron.
  • . y .. son entradas reales con su propio inodo, y por eso ./programa es la forma de ejecutar algo del directorio actual.
  • ls lo lees columna a columna, y conoces las combinaciones que se usan a diario: -lah, -ltr, -lhS y el imprescindible -ld.
  • tree -L te da la estructura de un vistazo sin ahogarte en profundidad.
  • stat te da los metadatos completos, y entiendes con precisión atime, mtime y ctime, incluida la razón por la que ctime es relevante en seguridad.
  • file te dice qué es realmente un archivo, porque en Linux la extensión no manda.
  • du mide lo que ocupa algo, df mide lo que queda, y sabes por qué a veces no cuadran y qué hacer cuando el disco «está lleno» sin estarlo.
  • Y has caracterizado el despliegue completo de Tramontana Reservas con cinco comandos, sin modificar nada.

Se acabó mirar. En la próxima lección, Operaciones con Archivos y Directorios, empiezas a escribir en el disco: touch y mkdir para crear, cp y mv con todas sus trampas —incluida la barra final del destino, que muerde a todo el mundo—, rm y la conversación seria sobre rm -rf que hay que tener una vez en la vida, rsync para copiar directorios grandes como es debido, y tar con gzip, bzip2 y xz para empaquetar. Terminarás preparando un paquete de /opt/tramontana/app para pasárselo a Luis. Asegúrate de tener el snapshot de la VM al día antes de empezar: a partir de aquí, los comandos ya no se limitan a mirar.

Curso de Linux: De Principiante a Administrador de Sistemas

Módulo 1: Introducción a Linux

Módulo 2: Comandos Básicos de Linux

Módulo 3: Habilidades Avanzadas en la Línea de Comandos

Módulo 4: Scripting en Shell

Módulo 5: Administración del Sistema

Módulo 6: Redes y Seguridad

Módulo 7: Temas Avanzados

Módulo 8: Proyectos Prácticos

© Copyright 2026. Todos los derechos reservados