0

Shell脚本curl批量请求实战:4种方法让网站巡检效率翻倍

2026.06.05 | youres | 24次围观

前言

做网站运维,少不了要批量检测一堆URL的状态。HTTP跳转正不正常、证书什么时候到期、某个接口响应快不快——这些问题靠浏览器一个个点,根本不现实。用Shell脚本配合curl,几行代码就能把重复劳动自动化。今天分享4种从简单到高级的批量请求方法,覆盖日常巡检的各个场景。

一、基础循环:for 和 while 两种写法

1.1 for 循环处理URL列表

最基础的写法,直接把URL写死在脚本里或者从文件读取:

# 直接写URL
for url in https://site-a.com https://site-b.com https://site-c.com; do
    echo "检测: $url"
    curl -o /dev/null -s -w "状态码:%{http_code} 耗时:%{time_total}s\n" "$url"
done

加上重定向检测(-L 跟随跳转,-s 静默):

for url in https://site-a.com https://site-b.com; do
    result=$(curl -o /dev/null -s -w "%{http_code}|%{time_total}|%{url_effective}" -L "$url")
    echo "$url -> $result"
done

1.2 while read 逐行读取文件

URL多的时候不适合写死在脚本里,存成文件一行一个,读取处理更灵活:

# urls.txt 每行一个URL
while IFS= read -r url; do
    status=$(curl -o /dev/null -s -w "%{http_code}" -L "$url")
    echo "$url | $status"
done < urls.txt

配合awk提取响应时间和状态码,做简单格式化:

while IFS= read -r url; do
    curl -o /dev/null -s -w "$url %{http_code} %{time_total}s\n" -L "$url"
done < urls.txt | awk '{print NR"|"$0}'

二、并行加速:让批量请求快10倍

顺序执行有个明显问题——10个URL每个耗时2秒,总共要等20秒。实际工作中经常要检测几十上百个域名,串行太慢了。并行处理能显著缩短总耗时。

2.1 xargs 并行

# 读取URL文件,4个并行执行
cat urls.txt | xargs -P 4 -I {} \
    bash -c 'url={}; status=$(curl -o /dev/null -s -w "%{http_code}" "$url"); echo "$url|$status"'

实用示例:批量检测状态码,超时控制10秒:

cat urls.txt | xargs -P 8 -I {} \
    bash -c 'url={}; status=$(curl -o /dev/null -s -w "%{http_code}" --connect-timeout 5 --max-time 10 "$url"); echo "$url|$status"' > status_results.txt

2.2 GNU Parallel(更强大)

# 安装:apt install parallel 或 yum install parallel
# 20个并行,--dry-run 先预览要执行什么命令
cat urls.txt | parallel -P 20 --dry-run 'curl -s -o /dev/null -w "%{url_effective}|%{http_code}|%{time_total}\n" {}'

去掉 --dry-run 实际执行:

# 实际运行:20并发,输出到结果文件
cat urls.txt | parallel -P 20 'curl -s -o /dev/null -w "%{url_effective}|%{http_code}|%{time_total}\n" {}' > results.txt

两者区别:xargs 是 GNU coreutils 自带的,大多数Linux系统直接可用;Parallel 需要单独安装,但支持更丰富的参数,如内存控制、任务控制、进度显示。巡检50个以内域名用 xargs 完全够用,超过100个域名建议上 Parallel。

三、输出格式化:让结果更易读

3.1 日志追加

log_batch() {
    local url=$1
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local result=$(curl -o /dev/null -s -w "%{http_code}|%{time_total}|%{url_effective}" -L "$url")
    echo "$timestamp|$url|$result" >> batch_result.log
}

while IFS= read -r url; do
    log_batch "$url"
done < urls.txt

echo "检测完成,共 $(wc -l < urls.txt) 个URL"

3.2 CSV 导出(Excel 直接打开)

# PowerShell 版:批量检测状态码并导出 CSV
$urls = @(
    'https://www.youres.cn',
    'https://httpbin.org/status/200',
    'https://httpbin.org/status/404'
)

$results = @()
foreach ($url in $urls) {
    try {
        $r = Invoke-WebRequest -Uri $url -MaximumRedirection 5 -TimeoutSec 10 -ErrorAction Stop
        $results += [PSCustomObject]@{
            URL = $url
            StatusCode = $r.StatusCode
            FinalURL = $r.BaseResponse.ResponseUri
            ResponseTime = [math]::Round(($r.Elapsed.TotalMilliseconds)/1000, 3)
        }
    } catch {
        $results += [PSCustomObject]@{
            URL = $url
            StatusCode = "ERROR"
            FinalURL = $_.Exception.Message
            ResponseTime = -1
        }
    }
}
$results | Export-Csv -Path results.csv -NoTypeInformation -Encoding UTF8

四、错误处理:让脚本更健壮

网络请求不可避免会遇到各种异常——DNS解析失败、连接超时、SSL证书问题。做好容错,脚本才能真正用于生产环境。

4.1 curl 退出码判断

check_url() {
    local url=$1
    # curl 退出码含义:
    # 0  - 成功(含4xx/5xx HTTP响应)
    # 22 - HTTP 4xx/5xx(服务器返回了错误页面)
    # 28 - 连接超时
    # 7  - 连接失败(服务器不可达)
    
    local output=$(curl -o /dev/null -s -w "%{http_code}|%{time_total}|%{url_effective}" \
        --connect-timeout 5 --max-time 15 -L "$url" 2>&1)
    local exit_code=$?
    
    if [ $exit_code -eq 0 ]; then
        echo "OK|$output"
    elif [ $exit_code -eq 28 ]; then
        echo "TIMEOUT|$url"
    elif [ $exit_code -eq 7 ]; then
        echo "CONN_FAIL|$url"
    else
        echo "ERROR|exit_$exit_code|$url"
    fi
}

# 处理结果:只告警非正常状态的
while IFS= read -r url; do
    result=$(check_url "$url")
    status=$(echo "$result" | awk -F'|' '{print $2}')
    
    if [ "$status" != "200" ] && [ "$status" != "301" ] && [ "$status" != "302" ]; then
        echo "告警: $url 状态 -> $result"
    fi
done < urls.txt

4.2 超时与重试机制

curl_retry() {
    local url=$1
    local max_try=3
    local try=0
    
    while [ $try -lt $max_try ]; do
        try=$((try+1))
        status=$(curl -o /dev/null -s -w "%{http_code}" \
            --connect-timeout 5 --max-time 10 "$url" 2>/dev/null)
        
        if [ $? -eq 0 ]; then
            echo "$url|$status"
            return 0
        fi
        
        echo "第${try}次失败,重试中..." >&2
        sleep 2
    done
    
    echo "$url|FAIL_AFTER_${max_try}_TRIES"
    return 1
}

五、性能优化:让脚本跑得更快

同样是批量请求,细节不同速度能差好几倍。

5.1 超时设置要合理

--connect-timeout 5 --max-time 15:连接超时5秒、总超时15秒。兼顾了速度和容错,不设超时的话一个卡住的请求会拖垮整个脚本。

5.2 静默模式

-s 静默模式关闭进度条和错误输出,减少终端I/O开销。对脚本批量执行尤为重要。

5.3 并行数的选择

并行50和并行100测同一个网站,可能后者反而更慢——并发太多会导致服务器限流或本地端口耗尽。建议从并行10-20开始测试,观察响应时间是否稳定后再调整。

5.4 只获取响应头

如果只需要检查状态,不需要完整响应体,用 -I--head 只发 HEAD 请求,速度更快、服务器压力更小:

cat urls.txt | xargs -P 10 -I {} \
    bash -c 'curl -I -s -o /dev/null -w "%{http_code}|%{time_total}|{}\n" --connect-timeout 5 --max-time 10 {}'

六、总结

Shell脚本配合curl做批量请求是运维工作中非常实用的技能。核心要点:

  • 顺序执行:用 forwhile read 逐条处理,适合调试和小批量场景
  • 并行加速xargs -PGNU Parallel,10个URL从20秒压缩到2-3秒
  • 输出格式化:加时间戳、状态码、响应时间,结果存入日志或CSV
  • 错误处理:检查curl退出码,超时和连接失败要单独处理
  • 性能调优:合理超时、静默模式、HEAD请求、并行数适中

掌握了这些技巧,无论是日常网站巡检、证书监控,还是批量重定向检测,都能用几行Shell脚本搞定。

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论