简介

cURL不仅是一个强大的HTTP客户端工具,也是一个优秀的文件下载工具。 它支持多种协议(HTTP、HTTPS、FTP、SFTP等),提供了丰富的下载选项和功能。

本指南将详细介绍如何使用cURL下载各种类型的文件,包括基础下载、断点续传、 批量下载、进度监控等高级功能,帮助你在不同场景下高效地完成文件下载任务。

基础文件下载

简单文件下载

最基本的文件下载命令:

# 下载文件到当前目录,保持原文件名
curl -O https://example.com/file.zip

# 下载文件并指定新文件名
curl -o myfile.zip https://example.com/file.zip

# 下载到指定目录
curl -o /downloads/file.zip https://example.com/file.zip

参数详解

# 跟随重定向下载
curl -L -O https://github.com/user/repo/archive/main.zip

# 同时下载多个文件
curl -O https://example.com/file1.zip -O https://example.com/file2.zip

# 下载并显示详细信息
curl -v -O https://example.com/file.zip

进度监控和显示

显示下载进度

# 显示进度条
curl --progress-bar -O https://example.com/largefile.zip

# 静默模式(不显示进度)
curl -s -O https://example.com/file.zip

# 显示详细的下载统计信息
curl -w "Downloaded: %{size_download} bytes in %{time_total} seconds\nSpeed: %{speed_download} bytes/sec\n" -o file.zip https://example.com/file.zip

自定义进度格式

# 创建进度格式文件
cat > curl_format.txt << 'EOF'
     time_namelookup:  %{time_namelookup}s
        time_connect:  %{time_connect}s
     time_appconnect:  %{time_appconnect}s
    time_pretransfer:  %{time_pretransfer}s
       time_redirect:  %{time_redirect}s
  time_starttransfer:  %{time_starttransfer}s
                     ----------
          time_total:  %{time_total}s
       size_download:  %{size_download} bytes
      speed_download:  %{speed_download} bytes/sec
EOF

# 使用自定义格式
curl -w "@curl_format.txt" -o file.zip https://example.com/file.zip

断点续传

基础断点续传

# 自动检测并续传
curl -C - -O https://example.com/largefile.zip

# 从指定位置开始下载(假设已下载1024字节)
curl -C 1024 -O https://example.com/largefile.zip

# 结合其他选项使用断点续传
curl -L -C - --progress-bar -O https://example.com/largefile.zip

智能续传脚本

#!/bin/bash
# 智能下载脚本,支持断点续传和重试

download_with_retry() {
    local url="$1"
    local output="$2"
    local max_retries=3
    local retry_count=0
    
    while [ $retry_count -lt $max_retries ]; do
        echo "尝试下载 (第 $((retry_count + 1)) 次): $url"
        
        # 使用断点续传下载
        if curl -L -C - --progress-bar -o "$output" "$url"; then
            echo "下载成功: $output"
            return 0
        else
            echo "下载失败,等待5秒后重试..."
            sleep 5
            retry_count=$((retry_count + 1))
        fi
    done
    
    echo "下载失败,已重试 $max_retries 次"
    return 1
}

# 使用示例
download_with_retry "https://example.com/largefile.zip" "largefile.zip"

批量下载

URL列表批量下载

# 创建URL列表文件
cat > urls.txt << 'EOF'
https://example.com/file1.zip
https://example.com/file2.pdf
https://example.com/file3.mp4
https://example.com/file4.tar.gz
EOF

# 方法1:使用xargs批量下载
cat urls.txt | xargs -n 1 -P 4 curl -L -O

# 方法2:使用while循环
while read url; do
    echo "正在下载: $url"
    curl -L -O "$url"
done < urls.txt

# 方法3:并行下载脚本
#!/bin/bash
while read url; do
    {
        filename=$(basename "$url")
        echo "开始下载: $filename"
        curl -L -C - --progress-bar -o "$filename" "$url"
        echo "完成下载: $filename"
    } &
done < urls.txt
wait  # 等待所有下载完成

范围下载(下载文件的一部分)

# 下载文件的前1024字节
curl -r 0-1023 -o partial.zip https://example.com/file.zip

# 下载从第1024字节开始的内容
curl -r 1024- -o remaining.zip https://example.com/file.zip

# 下载文件的中间部分(第1024到第2047字节)
curl -r 1024-2047 -o middle.zip https://example.com/file.zip

# 下载文件的最后1024字节
curl -r -1024 -o last_part.zip https://example.com/file.zip

认证下载

基础认证

# HTTP基础认证
curl -u username:password -O https://example.com/protected/file.zip

# 只提供用户名,密码交互式输入
curl -u username -O https://example.com/protected/file.zip

# 使用环境变量存储凭据
export CURL_USER="username:password"
curl -u "$CURL_USER" -O https://example.com/protected/file.zip

Bearer Token认证

# 使用Bearer Token
curl -H "Authorization: Bearer your_token_here" -O https://api.example.com/files/document.pdf

# 从文件读取token
TOKEN=$(cat token.txt)
curl -H "Authorization: Bearer $TOKEN" -O https://api.example.com/files/document.pdf

# API密钥认证
curl -H "X-API-Key: your_api_key" -O https://api.example.com/files/document.pdf

Cookie认证

# 使用cookie文件
curl -b cookies.txt -O https://example.com/protected/file.zip

# 直接设置cookie
curl -b "sessionid=abc123; csrftoken=xyz789" -O https://example.com/protected/file.zip

# 保存cookie到文件
curl -c cookies.txt -b cookies.txt -O https://example.com/protected/file.zip

FTP下载

基础FTP下载

# 匿名FTP下载
curl -O ftp://ftp.example.com/pub/file.zip

# 使用用户名和密码
curl -u username:password -O ftp://ftp.example.com/private/file.zip

# 列出FTP目录内容
curl ftp://ftp.example.com/pub/

# 下载整个目录(递归)
curl -u username:password -O ftp://ftp.example.com/directory/

SFTP/SCP下载

# SFTP下载
curl -u username:password -O sftp://example.com/path/to/file.zip

# 使用SSH密钥
curl --key ~/.ssh/id_rsa --pubkey ~/.ssh/id_rsa.pub -u username -O sftp://example.com/file.zip

# SCP下载
curl -u username:password -O scp://example.com/path/to/file.zip

高级下载选项

速度限制和超时

# 限制下载速度为100KB/s
curl --limit-rate 100k -O https://example.com/file.zip

# 设置连接超时(10秒)
curl --connect-timeout 10 -O https://example.com/file.zip

# 设置最大传输时间(300秒)
curl --max-time 300 -O https://example.com/file.zip

# 结合使用多个选项
curl --limit-rate 500k --connect-timeout 30 --max-time 600 -C - -L -O https://example.com/largefile.zip

代理设置

# 使用HTTP代理
curl --proxy http://proxy.example.com:8080 -O https://example.com/file.zip

# 使用SOCKS代理
curl --socks5 socks5://proxy.example.com:1080 -O https://example.com/file.zip

# 代理认证
curl --proxy-user username:password --proxy http://proxy.example.com:8080 -O https://example.com/file.zip

# 使用环境变量设置代理
export http_proxy=http://proxy.example.com:8080
export https_proxy=http://proxy.example.com:8080
curl -O https://example.com/file.zip

SSL/TLS选项

# 忽略SSL证书验证(不推荐用于生产环境)
curl -k -O https://example.com/file.zip

# 指定CA证书文件
curl --cacert /path/to/ca-cert.pem -O https://example.com/file.zip

# 使用客户端证书
curl --cert client.pem --key client.key -O https://example.com/file.zip

# 指定SSL版本
curl --tlsv1.2 -O https://example.com/file.zip

文件完整性验证

下载并验证校验和

#!/bin/bash
# 下载文件并验证MD5校验和

download_and_verify() {
    local url="$1"
    local expected_md5="$2"
    local filename=$(basename "$url")
    
    echo "正在下载: $filename"
    curl -L -C - --progress-bar -o "$filename" "$url"
    
    if [ $? -eq 0 ]; then
        echo "下载完成,正在验证校验和..."
        actual_md5=$(md5sum "$filename" | cut -d' ' -f1)
        
        if [ "$actual_md5" = "$expected_md5" ]; then
            echo "✓ 校验和验证成功"
            return 0
        else
            echo "✗ 校验和验证失败"
            echo "期望: $expected_md5"
            echo "实际: $actual_md5"
            return 1
        fi
    else
        echo "下载失败"
        return 1
    fi
}

# 使用示例
download_and_verify "https://example.com/file.zip" "d41d8cd98f00b204e9800998ecf8427e"

SHA256验证脚本

#!/bin/bash
# 下载文件并验证SHA256校验和

verify_sha256() {
    local file="$1"
    local expected_sha256="$2"
    
    if [ ! -f "$file" ]; then
        echo "文件不存在: $file"
        return 1
    fi
    
    actual_sha256=$(sha256sum "$file" | cut -d' ' -f1)
    
    if [ "$actual_sha256" = "$expected_sha256" ]; then
        echo "✓ SHA256校验成功: $file"
        return 0
    else
        echo "✗ SHA256校验失败: $file"
        echo "期望: $expected_sha256"
        echo "实际: $actual_sha256"
        return 1
    fi
}

# 下载并验证
URL="https://example.com/file.zip"
EXPECTED_SHA256="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
FILENAME=$(basename "$URL")

curl -L -C - -o "$FILENAME" "$URL" && verify_sha256 "$FILENAME" "$EXPECTED_SHA256"

下载自动化

监控下载脚本

#!/bin/bash
# 高级下载脚本,包含日志记录和错误处理

DOWNLOAD_DIR="./downloads"
LOG_FILE="download.log"
MAX_RETRIES=3
RETRY_DELAY=5

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

download_file() {
    local url="$1"
    local output_dir="$2"
    local retry_count=0
    
    local filename=$(basename "$url")
    local output_path="$output_dir/$filename"
    
    # 创建输出目录
    mkdir -p "$output_dir"
    
    log "开始下载: $url"
    
    while [ $retry_count -lt $MAX_RETRIES ]; do
        log "尝试 #$((retry_count + 1)): $filename"
        
        # 检查是否存在部分下载的文件
        if [ -f "$output_path" ]; then
            local file_size=$(stat -c%s "$output_path" 2>/dev/null || echo 0)
            log "发现已存在文件,大小: $file_size 字节,尝试续传"
        fi
        
        # 执行下载
        if curl -L -C - --connect-timeout 30 --max-time 3600 \
                --progress-bar -o "$output_path" "$url" 2>>"$LOG_FILE"; then
            log "✓ 下载成功: $filename"
            
            # 验证文件大小
            local final_size=$(stat -c%s "$output_path")
            log "最终文件大小: $final_size 字节"
            
            return 0
        else
            retry_count=$((retry_count + 1))
            log "✗ 下载失败,等待 $RETRY_DELAY 秒后重试..."
            
            if [ $retry_count -lt $MAX_RETRIES ]; then
                sleep $RETRY_DELAY
            fi
        fi
    done
    
    log "✗ 下载失败,已达到最大重试次数: $filename"
    return 1
}

# 批量下载函数
batch_download() {
    local url_file="$1"
    local output_dir="$2"
    local success_count=0
    local total_count=0
    
    log "开始批量下载,URL文件: $url_file"
    
    while IFS= read -r url; do
        # 跳过空行和注释
        if [[ -z "$url" || "$url" =~ ^[[:space:]]*# ]]; then
            continue
        fi
        
        total_count=$((total_count + 1))
        
        if download_file "$url" "$output_dir"; then
            success_count=$((success_count + 1))
        fi
        
        log "进度: $success_count/$total_count 成功"
    done < "$url_file"
    
    log "批量下载完成: $success_count/$total_count 成功"
    
    if [ $success_count -eq $total_count ]; then
        return 0
    else
        return 1
    fi
}

# 使用示例
if [ $# -eq 0 ]; then
    echo "用法:"
    echo "  $0                     # 下载单个文件"
    echo "  $0 -f             # 批量下载"
    echo "  $0 -d             # 指定下载目录"
    exit 1
fi

case "$1" in
    -f)
        batch_download "$2" "$DOWNLOAD_DIR"
        ;;
    -d)
        download_file "$3" "$2"
        ;;
    *)
        download_file "$1" "$DOWNLOAD_DIR"
        ;;
esac

故障排除

常见问题和解决方案

1. 连接超时问题

# 增加超时时间和重试
curl --connect-timeout 60 --max-time 3600 --retry 3 --retry-delay 10 -L -C - -O https://example.com/file.zip

2. SSL证书问题

# 更新CA证书
curl --cacert /etc/ssl/certs/ca-certificates.crt -O https://example.com/file.zip

# 临时忽略证书验证(仅用于测试)
curl -k -O https://example.com/file.zip

3. 重定向问题

# 跟随重定向并限制重定向次数
curl -L --max-redirs 5 -O https://example.com/file.zip

4. 用户代理问题

# 设置常见的用户代理
curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" -O https://example.com/file.zip

调试技巧

# 详细输出调试信息
curl -v -O https://example.com/file.zip

# 只显示响应头
curl -I https://example.com/file.zip

# 跟踪重定向
curl -L -v -o /dev/null https://example.com/file.zip

# 保存调试信息到文件
curl -v -o file.zip https://example.com/file.zip 2> debug.log

最佳实践

1. 安全下载

安全建议:

  • 始终验证下载文件的校验和
  • 使用HTTPS而不是HTTP
  • 避免禁用SSL验证
  • 小心处理用户输入的URL
  • 设置合理的超时时间

2. 性能优化

性能提示:

  • 使用断点续传减少重复下载
  • 合理设置并发下载数量
  • 根据网络条件调整重试策略
  • 使用进度监控了解下载状态
  • 考虑使用代理加速下载

3. 脚本编写规范

#!/bin/bash
# 良好的下载脚本模板

set -euo pipefail  # 严格模式

# 配置变量
readonly SCRIPT_NAME=$(basename "$0")
readonly LOG_FILE="${SCRIPT_NAME%.sh}.log"
readonly DOWNLOAD_DIR="./downloads"
readonly MAX_RETRIES=3

# 错误处理
trap 'echo "脚本异常退出,请检查日志: $LOG_FILE" >&2' ERR

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

# 参数验证
validate_url() {
    local url="$1"
    if [[ ! "$url" =~ ^https?:// ]]; then
        log "错误: 无效的URL: $url"
        return 1
    fi
}

# 主要下载逻辑
main() {
    if [ $# -eq 0 ]; then
        echo "用法: $SCRIPT_NAME "
        exit 1
    fi
    
    local url="$1"
    validate_url "$url"
    
    # 下载逻辑...
}

main "$@"

总结

cURL是一个功能强大的文件下载工具,支持多种协议和高级功能。通过掌握本指南中的技巧,你可以:

记住始终关注安全性、错误处理和用户体验,编写健壮可靠的下载脚本。 合理使用cURL的各种选项,可以应对大多数文件下载场景的需求。