`which`, `type` y `command -v`: localizar ejecutables

Cuando escribes python3 en la terminal y la shell lo ejecuta, no está buscando ese nombre en todo el disco. Está recorriendo una lista de directorios llamada PATH — una variable de entorno que contiene rutas separadas por dos puntos — y ejecuta el primer archivo que encuentra con ese nombre. Si escribes python y obtienes command not found, el problema casi siempre es este: el ejecutable no está en ninguno de esos directorios, o existe con un nombre distinto.

El PATH típico en Debian tiene este aspecto:

/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin

La shell los recorre de izquierda a derecha y se detiene en la primera coincidencia. Eso significa que el orden importa: si tienes dos versiones del mismo programa en directorios distintos, gana la que aparece primero.

Para saber exactamente qué va a ejecutar la shell cuando escribes un nombre, tienes tres herramientas: which, type y command -v. No son intercambiables — cada una responde a una pregunta ligeramente distinta, y confundirlas lleva a diagnósticos incorrectos.

which es un programa externo (un binario en /usr/bin/which) que busca en el PATH y devuelve la ruta del ejecutable. Solo ve archivos en el sistema de ficheros; no conoce los alias ni las funciones que has definido en tu sesión de bash. Si has creado alias ls='ls --color=auto', which ls te devolverá /usr/bin/ls — correcto como ruta, pero incompleto como diagnóstico, porque eso no es lo que bash ejecuta cuando escribes ls.

type es un built-in de bash, es decir, no es un programa externo sino un comando que bash ejecuta directamente desde su propio código. Por eso tiene acceso a toda la información interna de la shell: sabe si algo es un alias, una función definida en tu .bashrc, un built-in de bash como cd, o un ejecutable en el disco. Es la herramienta correcta para diagnóstico interactivo.

command -v es la versión portátil especificada por POSIX. Funciona igual en sh, dash, bash y cualquier shell compatible. Cuando escribes scripts que deben correr en entornos donde no sabes qué shell está disponible — un hook de git, un script de instalación, un contenedor mínimo — command -v es lo que debes usar.

Si te equivocas de herramienta, el diagnóstico falla silenciosamente: which te dirá que un comando existe, pero la shell ejecutará en realidad otra cosa (el alias o la función); o usarás type en un script sh y obtendrás un error porque ese shell no lo implementa.

Ejemplo completo

# Situación: tienes varios "python" en el sistema y quieres saber
# exactamente qué ejecuta tu shell en cada caso.

# 1. Ver el PATH actual, directorios separados por ":"
echo "$PATH"

# 2. which: busca solo ejecutables en el PATH, ignora alias y funciones
which python3
which python          # probablemente falla en Debian — python2 no está por defecto

# 3. type: built-in de bash, muestra TODO: alias, funciones, built-ins, ejecutables
type python3          # → python3 is /usr/bin/python3
type ls               # → ls is aliased to `ls --color=auto` (si tienes el alias)
type cd               # → cd is a shell builtin
type ll               # → ll is aliased to `ls -l --color=auto` (si existe el alias)

# 4. type -a: muestra TODAS las coincidencias, no solo la primera
# Útil cuando sospechas que hay varios python3 en distintos directorios
type -a python3

# 5. command -v: versión POSIX, la correcta para scripts
command -v python3    # → /usr/bin/python3
command -v cd         # → cd  (para built-ins solo devuelve el nombre)

# 6. Uso típico en un script portable: comprobar si un comando existe
# La redirección a /dev/null suprime la salida; solo nos interesa el código de salida
if command -v git > /dev/null 2>&1; then
    echo "git está disponible"
else
    echo "git no está instalado"
fi

# 7. Crear un alias temporal y ver la diferencia entre which y type
alias python='python3'
which python          # → /usr/bin/python  (si existe) o nada — NO ve el alias
type python           # → python is aliased to 'python3'  — SÍ ve el alias

Qué está pasando en cada paso

El echo "$PATH" del principio no es decorativo — antes de diagnosticar cualquier problema con un ejecutable, necesitas saber qué directorios está consultando tu shell. Si /usr/local/bin aparece antes que /usr/bin, un ejecutable instalado manualmente ahí tendrá prioridad sobre el del sistema.

El which python del paso 2 probablemente no devuelve nada en Debian Bookworm porque el paquete python2 no está instalado por defecto y python3 no crea un enlace simbólico llamado python a menos que instales el paquete python-is-python3. Este es exactamente el problema descrito al principio: el binario existe, pero con otro nombre.

La diferencia entre type ls y which ls en el paso 3 es el caso más frecuente de confusión. El .bashrc de Debian incluye alias ls='ls --color=auto' por defecto, así que which ls y type ls devuelven información distinta — ambas verdaderas, pero respondiendo preguntas distintas.

type -a python3 del paso 4 es especialmente útil cuando usas entornos virtuales de Python o tienes versiones instaladas en /usr/local/bin por compilación manual. Te muestra toda la cadena de candidatos en orden de prioridad, no solo el ganador.

El bloque if command -v git del paso 6 es el patrón correcto para scripts. Usar which aquí es un error habitual: en algunos sistemas which devuelve un código de salida 0 incluso cuando no encuentra el comando, lo que rompe la lógica del if. command -v se comporta de forma consistente según POSIX: código 0 si lo encuentra, código distinto de 0 si no.

El paso 7 demuestra por qué which no sirve para diagnóstico completo en sesiones interactivas. Después de definir alias python='python3', which python sigue sin encontrarlo (porque busca un archivo llamado python en el PATH, no el alias), mientras que type python muestra exactamente lo que bash va a hacer. Si estás depurando por qué un comando se comporta de forma inesperada en tu terminal, type es siempre el punto de partida correcto.

14

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio