curl es la herramienta definitiva para comunicación HTTP desde la línea de comandos. curl URL envía un GET, -X POST -d '{...}' envía datos a una API, -v muestra la traza completa de la petición/respuesta — prácticamente cualquier operación HTTP en un solo comando.
¿Necesitas probar un endpoint de API desde la terminal? ¿Depurar una cadena de redirecciones? ¿Lanzar un webhook desde un script de CI?
curl lo maneja todo. Viene preinstalado en Linux y macOS, y funciona en Windows a través de WSL o Git Bash.
Esta guía cubre todo, desde lo básico hasta scripting del mundo real, con ejemplos listos para ejecutar.
¿Qué es curl?
curl (abreviatura de "Client URL") es una herramienta de línea de comandos para transferir datos usando URLs. Soporta más de 20 protocolos incluyendo HTTP, HTTPS, FTP, SFTP y SCP. Fue creado por Daniel Stenberg en 1998 y sigue siendo uno de los proyectos de código abierto con mantenimiento más activo.
Características clave:
- Navaja suiza de HTTP: soporta GET, POST, PUT, DELETE, PATCH y todos los demás métodos
- Salida flexible: obtén solo las cabeceras, solo el cuerpo, mide tiempos de respuesta o captura todo
- libcurl: también disponible como biblioteca en C, utilizada por Python, PHP, Ruby y muchos otros lenguajes internamente
- Multiplataforma: funciona en Linux, macOS y Windows
Cómo se compara con wget: wget está construido para descargar archivos — destaca en descargas recursivas y espejos de sitios. curl es la herramienta HTTP de propósito general — brilla en llamadas a API, inspección de respuestas y creación de peticiones complejas.
Para una comparación detallada, consulta la Guía completa de wget.
Uso básico
Verificar la instalación
Verifica que curl está disponible en tu sistema.
curl --version
Si usas WSL (Windows Subsystem for Linux), la versión de Linux de curl está disponible. Git Bash también incluye curl. Ten en cuenta que el curl de PowerShell es un alias de Invoke-WebRequest — no es la misma herramienta.
# WSL (Ubuntu)
sudo apt install curl
Petición GET
curl https://example.com
El cuerpo de la respuesta se imprime en stdout. Para guardar en un archivo:
# Guardar con un nombre personalizado
curl -o output.html https://example.com
# Guardar usando el nombre del archivo de la URL
curl -O https://example.com/file.zip
Inspeccionar cabeceras de respuesta
# Solo cabeceras (petición HEAD)
curl -I https://example.com
# Cabeceras + cuerpo juntos
curl -i https://example.com
Modo verbose (depuración)
curl -v https://example.com
Esto muestra la conversación completa: handshake TLS, cabeceras de petición, cabeceras de respuesta y cuerpo. Esencial para diagnosticar problemas de conexión.
Modo silencioso
# Suprimir barra de progreso y mensajes de error
curl -s https://example.com
# Mostrar progreso como caracteres # (útil para archivos grandes)
curl -# -O https://example.com/file.zip
Referencia de opciones comunes
| Opción | Qué hace |
|---|---|
-o ARCHIVO | Guardar salida en ARCHIVO |
-O | Guardar usando el nombre de archivo de la URL |
-I / --head | Obtener solo cabeceras (petición HEAD) |
-i | Incluir cabeceras de respuesta en la salida |
-v / --verbose | Mostrar petición/respuesta completa (incluyendo TLS) |
-s / --silent | Suprimir progreso y errores |
-L / --location | Seguir redirecciones |
-X MÉTODO | Especificar método HTTP (POST, PUT, DELETE, etc.) |
-H "Cabecera: Valor" | Añadir cabecera personalizada |
-d "datos" | Enviar datos POST |
-u usuario:contraseña | Autenticación básica |
-k / --insecure | Omitir verificación de certificado SSL |
-c ARCHIVO | Guardar cookies en ARCHIVO |
-b ARCHIVO | Enviar cookies desde ARCHIVO |
--limit-rate VELOCIDAD | Limitar velocidad de transferencia (ej. --limit-rate 1M) |
-w "formato" | Formato de salida personalizado para info de respuesta |
--connect-timeout SEG | Timeout de conexión en segundos |
-C - | Reanudar descarga interrumpida |
-F "clave=@archivo" | Subir archivo como datos de formulario |
Casos de uso reales
Llamadas REST API (GET / POST / PUT / DELETE)
Los patrones que más usarás al probar APIs.
Enviar datos JSON con POST:
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}' \
https://api.example.com/users
Autenticarse con un token Bearer:
curl -s \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
https://api.example.com/me
Actualizar un recurso con PUT:
curl -s -X PUT \
-H "Content-Type: application/json" \
-d '{"name": "Alice Updated"}' \
https://api.example.com/users/123
Eliminar un recurso:
curl -s -X DELETE \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
https://api.example.com/users/123
Canalizar a jq para salida formateada:
curl -s https://api.example.com/users | jq '.data[] | {id, name}'
Para más sobre procesamiento de salida JSON, consulta la Guía completa de jq.
Depuración de cabeceras y redirecciones
Inspeccionar el handshake TLS completo y cabeceras:
curl -v https://example.com 2>&1 | head -30
La salida verbose va a stderr, así que 2>&1 la fusiona con stdout para canalizar a head.
Medir el desglose del tiempo de respuesta:
curl -o /dev/null -s -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\n" https://example.com
Esto muestra la resolución DNS, conexión TCP, handshake TLS y tiempo total por separado — ideal para identificar cuellos de botella de rendimiento.
Trazar la cadena de redirecciones:
curl -s -L -o /dev/null -w "URL final: %{url_effective}\nRedirecciones: %{num_redirects}\n" https://example.com
Subida de archivos
Subir un archivo como datos de formulario:
curl -F "file=@photo.jpg" https://api.example.com/upload
Subir múltiples archivos a la vez:
curl -F "file1=@document.pdf" \
-F "file2=@image.png" \
-F "description=Monthly report" \
https://api.example.com/upload
Especificar el tipo MIME explícitamente:
curl -F "file=@data.csv;type=text/csv" https://api.example.com/import
Gestión de cookies
Mantener sesiones entre peticiones, como después de iniciar sesión.
# Paso 1: Iniciar sesión y guardar cookies
curl -c cookies.txt \
-d "username=admin&password=secret" \
https://example.com/login
# Paso 2: Usar cookies guardadas para peticiones posteriores
curl -b cookies.txt https://example.com/dashboard
# Paso 3: Enviar cookies existentes y guardar las nuevas
curl -b cookies.txt -c cookies.txt https://example.com/profile
Reanudar descargas interrumpidas
Cuando una descarga grande se corta:
# Descarga original (interrumpida por Ctrl+C, caída de red, etc.)
curl -O https://example.com/largefile.iso
# Reanudar desde donde se quedó
curl -C - -O https://example.com/largefile.iso
El flag -C - le dice a curl que auto-detecte el tamaño actual del archivo y solicite solo los bytes restantes.
Técnicas avanzadas
Simplificar llamadas JSON API con --json
El flag --json (curl 7.82+) condensa el patrón estándar de API JSON en una sola opción.
# Enfoque tradicional (tres opciones necesarias)
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"name": "Alice"}' \
https://api.example.com/users
# --json lo hace todo en uno
curl -s --json '{"name": "Alice"}' https://api.example.com/users
--json internamente configura -d (POST), Content-Type: application/json y Accept: application/json. También lee desde archivos y stdin.
# Enviar JSON desde un archivo
curl --json @payload.json https://api.example.com/users
# Pasar JSON por pipe
echo '{"status": "active"}' | curl --json @- https://api.example.com/users/123
Reintentos integrados con --retry
No necesitas escribir bucles de reintento en scripts — curl tiene --retry integrado.
# Reintentar hasta 3 veces en errores transitorios (backoff automático)
curl --retry 3 --retry-delay 2 https://api.example.com/data
# Reintentar en todos los errores incluyendo 4xx/5xx
curl --retry 3 --retry-all-errors https://api.example.com/data
# Limitar el tiempo total de reintentos
curl --retry 5 --retry-max-time 60 https://api.example.com/data
Por defecto, curl reintenta en timeouts de conexión, HTTP 408, HTTP 429 y HTTP 5xx. Añade --retry-all-errors para incluir errores de red y otros fallos.
Peticiones paralelas (--parallel)
curl 7.66+ soporta --parallel (-Z) para peticiones concurrentes a múltiples URLs.
# Solicitar 4 APIs en paralelo
curl -Z -s \
-o users.json "https://api.example.com/users" \
-o posts.json "https://api.example.com/posts" \
-o comments.json "https://api.example.com/comments" \
-o tags.json "https://api.example.com/tags"
# Limitar conexiones concurrentes máximas
curl -Z --parallel-max 3 -s \
-o file1.zip "https://example.com/file1.zip" \
-o file2.zip "https://example.com/file2.zip" \
-o file3.zip "https://example.com/file3.zip" \
-o file4.zip "https://example.com/file4.zip" \
-o file5.zip "https://example.com/file5.zip"
El valor por defecto de --parallel-max es 50. Ajústalo según los límites de tasa de la API.
Configuraciones reutilizables con -K
En lugar de escribir opciones largas cada vez, guárdalas en un archivo de configuración.
# ~/.curl/api-config
header = "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
header = "Content-Type: application/json"
header = "Accept: application/json"
silent
location
connect-timeout = 10
max-time = 30
# Usar el archivo de configuración
curl -K ~/.curl/api-config https://api.example.com/users
# Archivo de configuración + opciones adicionales
curl -K ~/.curl/api-config --json '{"name": "Alice"}' https://api.example.com/users
Comparte archivos de configuración en el equipo para estandarizar los flujos de pruebas de API. Para ejecutar verificaciones de salud programadas, combínalo con cron / systemd timer.
Variables prácticas de -w
-w (--write-out) tiene variables útiles más allá del tiempo de respuesta.
# Mostrar información detallada de la respuesta
curl -s -o /dev/null -w "\
HTTP/%{http_version} %{http_code}\n\
Size: %{size_download} bytes\n\
Content-Type: %{content_type}\n\
Connections: %{num_connects}\n\
IP: %{remote_ip}:%{remote_port}\n\
" https://example.com
HTTP/2 200
Size: 12345 bytes
Content-Type: text/html; charset=utf-8
Connections: 1
IP: 93.184.215.14:443
# Salida en formato JSON (combinar con jq)
curl -s -o /dev/null -w '{
"status": %{http_code},
"time_total": %{time_total},
"size": %{size_download},
"ip": "%{remote_ip}"
}' https://example.com | jq '.'
Ejemplos de scripting
curl se combina naturalmente con scripts de shell. Para los fundamentos de scripting, consulta la Guía práctica de shell script.
Verificador de salud de APIs
Un script que comprueba el estado de múltiples endpoints e informa de fallos.
#!/bin/bash
ENDPOINTS=(
"https://api.example.com/health"
"https://api.example.com/v2/status"
"https://cdn.example.com/ping"
"https://auth.example.com/health"
)
echo "=== Verificación de Salud de API ==="
echo ""
FAILED=0
for URL in "${ENDPOINTS[@]}"; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 "$URL")
if [ "$STATUS" -ge 200 ] && [ "$STATUS" -lt 300 ]; then
echo "[OK] $STATUS $URL"
else
echo "[FAIL] $STATUS $URL"
FAILED=$((FAILED + 1))
fi
done
echo ""
echo "Resultados: $((${#ENDPOINTS[@]} - FAILED))/${#ENDPOINTS[@]} pasaron"
if [ "$FAILED" -gt 0 ]; then
exit 1
fi
Descargador por lotes con reintentos
#!/bin/bash
URLS=(
"https://example.com/data/january.csv"
"https://example.com/data/february.csv"
"https://example.com/data/march.csv"
)
DEST_DIR="./downloads"
MAX_RETRIES=3
mkdir -p "$DEST_DIR"
for URL in "${URLS[@]}"; do
FILENAME=$(basename "$URL")
ATTEMPT=1
while [ "$ATTEMPT" -le "$MAX_RETRIES" ]; do
echo "Descargando $FILENAME (intento $ATTEMPT/$MAX_RETRIES)..."
if curl -s -f -L -o "${DEST_DIR}/${FILENAME}" --connect-timeout 10 --max-time 120 "$URL"; then
echo " OK: $FILENAME"
break
else
echo " FALLÓ: $FILENAME"
ATTEMPT=$((ATTEMPT + 1))
if [ "$ATTEMPT" -le "$MAX_RETRIES" ]; then
echo " Reintentando en 5 segundos..."
sleep 5
fi
fi
done
if [ "$ATTEMPT" -gt "$MAX_RETRIES" ]; then
echo " ABANDONADO: $FILENAME después de $MAX_RETRIES intentos"
fi
done
echo "Hecho."
Consideraciones de seguridad
Actualizaciones de seguridad de curl
curl 8.19.0 (lanzado el 11 de marzo de 2026) es la versión más reciente. La anterior 8.18.0 (7 de enero de 2026) incluyó 6 correcciones de seguridad.
El programa de bug bounty de curl terminó a finales de enero de 2026. La avalancha de informes generados por IA hizo que la tasa de confirmación cayera por debajo del 5%, consumiendo recursos de triaje desproporcionados. Durante sus ~6 años de funcionamiento (desde abril de 2019), el programa confirmó 87 vulnerabilidades y pagó más de $100,000 en recompensas.
Nunca uses -k en producción
# Solo para entornos de prueba con certificados autofirmados
curl -k https://self-signed.example.com/api
-k (--insecure) desactiva la verificación de certificados SSL. Está bien para probar con certificados autofirmados, pero usarlo en producción o scripts automatizados te expone a ataques man-in-the-middle.
Mantén las credenciales fuera de los comandos
# Mal: contraseña visible en el historial del shell
curl -u admin:P@ssw0rd https://api.example.com/admin
# Bien: usar .netrc
echo "machine api.example.com login admin password P@ssw0rd" > ~/.netrc
chmod 600 ~/.netrc
curl -n https://api.example.com/admin
Siempre establece los permisos de .netrc a 600 para que otros usuarios no puedan leerlo.
Las variables de entorno también funcionan:
curl -u "admin:${API_PASSWORD}" https://api.example.com/admin
Preguntas frecuentes (FAQ)
¿Cuándo debo usar curl vs wget?
curl destaca en llamadas API, depuración HTTP y creación de peticiones complejas. wget destaca en descargas recursivas y espejos de sitios. Para probar APIs, usa curl. Para descargas masivas de archivos, usa wget. Consulta la Guía práctica de wget para una comparación detallada.
¿Cuál es la forma más simple de enviar JSON con curl?
Con curl 7.82+, usa curl --json '{"key": "value"}' URL. El flag --json configura Content-Type, Accept y -d de una vez. En versiones anteriores, necesitas -X POST -H "Content-Type: application/json" -d '{...}'.
¿Cómo diagnostico respuestas lentas de curl?
Usa curl -o /dev/null -s -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\n" URL para medir la resolución DNS, conexión TCP, handshake TLS y tiempo total individualmente. Esto identifica en qué fase está el cuello de botella.
¿Es seguro usar curl -k (--insecure) en producción?
No. -k omite la verificación de certificados SSL, lo que te expone a ataques man-in-the-middle. Solo úsalo temporalmente en entornos de prueba con certificados autofirmados. En producción, usa certificados válidos o especifica un certificado CA con --cacert.
¿Cómo subo archivos con curl?
Usa curl -F "file=@nombre_archivo" URL para subidas como datos de formulario. Especifica tipos MIME con curl -F "file=@datos.csv;type=text/csv" URL. Añade múltiples flags -F para varios archivos.
¿Cómo evito que las contraseñas queden en el historial del shell?
Almacena las credenciales en un archivo .netrc y usa curl -n URL. Establece los permisos de .netrc con chmod 600. Las variables de entorno también funcionan: curl -u "user:${PASSWORD}" URL.
¿Cómo añado reintentos automáticos a curl?
Usa curl --retry 3 --retry-delay 2 URL para reintentos automáticos en errores transitorios. Añade --retry-all-errors para reintentar también en respuestas 4xx/5xx. No necesitas escribir bucles de reintento en tus scripts.
¿Cómo verifico mi versión de curl?
Ejecuta curl --version. La última versión está disponible en la página de descargas oficial de curl. A marzo de 2026, la más reciente es 8.19.0.
Artículos relacionados
- Guía completa de jq —
curl | jqpara procesar JSON de respuestas API. El mejor compañero de curl - Guía práctica de wget — descargador de archivos dedicado. Cuándo usar wget vs curl
- Guía práctica de shell script — fundamentos de automatización con scripts para flujos de trabajo con curl
- Guía práctica de SSH y rsync — operaciones en servidores remotos. curl + SSH para automatización de APIs
- Guía práctica de xargs — procesar múltiples URLs en lote con curl
- Guía práctica de grep y ripgrep — búsqueda de texto en la salida de curl
- Kit de herramientas CLI — el panorama general de herramientas CLI y cuándo usar cada una
Conclusión
curl es la navaja suiza de la comunicación HTTP. Ya sea que estés probando APIs, depurando conexiones, subiendo archivos o escribiendo flujos de trabajo automatizados, es la herramienta de referencia.
Referencia rápida de los patrones más útiles:
- Petición básica:
curl URL. Guardar en archivo:-oo-O - Llamadas API:
--json '{...}'(7.82+) es lo más simple - Depuración:
-vpara traza completa,-wpara tiempos de respuesta - En scripts: siempre usa
-s -fpara modo silencioso + detección de errores - Credenciales: usa
.netrco variables de entorno, nunca las pongas directamente en comandos - Mantente actualizado: revisa curl.se regularmente para nuevas versiones
Si tu necesidad principal es descargar archivos, wget es más sencillo para esa tarea. Para llamadas API, inspección de respuestas y trabajo HTTP complejo, curl es la elección clara. Usa ambos — cada uno tiene sus fortalezas.