Cuando el sistema de archivos no tiene todavía la estructura que necesitas, la construyes tú. mkdir crea directorios y touch crea archivos vacíos o manipula sus marcas de tiempo. Son dos comandos de uso diario que esconden más lógica de la que parece a simple vista.
mkdir (make directory) llama internamente a la syscall mkdir(2), que reserva una entrada en el directorio padre y crea la estructura de metadatos del nuevo directorio. La parte importante: el directorio padre tiene que existir antes de que puedas crear un hijo. Si intentas hacer mkdir proyecto/src/utils y proyecto/ todavía no existe, el comando falla con un error. Ahí entra la opción -p (parents): recorre la ruta de izquierda a derecha y crea cada segmento que falte, saltándose los que ya existen. En scripts esto es la norma, no la excepción, porque un script que falla si el directorio ya existe es un script frágil.
touch tiene dos funciones distintas que se confunden fácilmente. La primera es la que todo el mundo conoce: si el archivo no existe, lo crea vacío. La segunda es su propósito original y el que le da el nombre: si el archivo ya existe, no lo modifica en absoluto, pero actualiza sus timestamps de acceso (atime) y modificación (mtime) al momento actual. Esto es relevante en sistemas de compilación como make, que decide qué recompilar comparando timestamps: si tocas un archivo cabecera, make lo interpreta como “este archivo cambió” aunque el contenido sea idéntico. Esa es la razón por la que existe touch.
Equivocarse aquí tiene consecuencias concretas. Usar mkdir sin -p en un script hace que falle la primera vez que la ruta padre no existe. Y confundir touch archivo con > archivo es un error que puede costarte datos: el operador de redirección > trunca el archivo a cero bytes si ya existe, mientras que touch lo deja intacto.
#!/bin/bash
# Estructura de un proyecto de ejemplo
# Crear toda la jerarquía de una vez; -p no falla si ya existe algún nivel
mkdir -p proyecto/{src,tests,docs,build}
# Crear archivos iniciales vacíos
touch proyecto/src/main.c
touch proyecto/docs/README.md
# Crear varios archivos de una vez pasando múltiples argumentos
touch proyecto/tests/{test_uno.c,test_dos.c}
# Ver los timestamps recién asignados
ls -l proyecto/src/main.c
# touch sobre un archivo existente: el contenido no cambia, solo el mtime
echo "código real" > proyecto/src/main.c
touch proyecto/src/main.c
# El archivo sigue teniendo "código real", pero mtime es ahora mismo
ls -l proyecto/src/main.c
# touch -t permite fijar un timestamp arbitrario (formato: [[CC]YY]MMDDhhmm[.ss])
# Útil para simular que un archivo es más antiguo o más nuevo que otro
touch -t 202401150900 proyecto/docs/README.md
ls -l proyecto/docs/README.md
# Diferencia crítica: > trunca, touch no
echo "datos importantes" > proyecto/build/output.bin
> proyecto/build/output.bin # output.bin ahora tiene 0 bytes — datos perdidos
# La forma segura de garantizar que un archivo existe sin destruirlo:
touch proyecto/build/output.bin # Si existiera con datos, los conservaría
La expansión {src,tests,docs,build} que usa mkdir -p es expansión de llaves del shell, no funcionalidad de mkdir; el shell genera cuatro rutas separadas antes de llamar al comando. Por eso funciona igual con touch en la línea de los tests.
La opción -p de mkdir hace dos cosas a la vez: crea los niveles intermedios que falten y suprime el error si el directorio final ya existe. Sin ella, un script que se ejecuta dos veces falla en la segunda ejecución.
El bloque con touch -t 202401150900 establece el timestamp al 15 de enero de 2024 a las 09:00. El formato MMDDhhmm es fijo; los dos dígitos del siglo (CC) y los segundos (.ss) son opcionales. Esto se usa en pruebas de sistemas de build donde necesitas controlar el orden relativo de modificación entre archivos sin cambiar su contenido.
La línea > proyecto/build/output.bin ilustra el peligro: la redirección vacía es una forma habitual de “limpiar” un archivo de log, pero si la aplicas al archivo equivocado, los datos desaparecen sin aviso ni papelera de reciclaje. touch nunca hace eso.
N° 19