You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Bash脚本中实现多线程以加速文本文件URL的curl请求?

在Bash中实现多线程加速curl循环的方法

首先得说一下,你现在脚本里加的&其实有问题——因为HTTP_RESPONSE这些变量是全局的,多个后台进程会同时修改它们,最后日志里的内容大概率是混乱的,根本达不到正确的并行效果。下面给你几种靠谱的实现方式,既能提速又能保证数据正确:

方法1:用xargs实现并行(最简单易上手)

xargs本身就支持并行参数,只需要把单站点处理逻辑封装成函数,再用xargs批量调用就行,代码改动很小:

SECRET_KEY='zuhahaha'
FILE_NAME=""
case "$1" in
    "sma") FILE_NAME="sma.txt" ;;
    "smk") FILE_NAME="smk.txt" ;;
    "smp") FILE_NAME="smp.txt" ;;
    "sd") FILE_NAME="sd.txt" ;;
    *) echo "not in case !" && exit 1 ;;
esac

# 封装单个站点的处理逻辑,用局部变量避免冲突
process_site() {
    local line="$1"
    local HTTP_RESPONSE=$(curl -L -s -w "HTTPSTATUS:%{http_code}\\n" -H "X-Gitlab-Event: Push Hook" -H "X-Gitlab-Token: $SECRET_KEY" --insecure "$line" 2>&1)
    local HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
    local HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
    
    # 加锁写日志,防止多个进程同时写导致内容错乱
    flock -x output.log -c "
        printf '%s\n' \
            \"Header Code : $HTTP_STATUS\" \
            \"Executed at : $(date)\" \
            \"Response Body : $HTTP_BODY\" \
            \"=====================================================================================================\" \
            \"\" >> output.log
    "
}

# 导出函数和环境变量,让xargs的子进程能访问到
export -f process_site
export SECRET_KEY

# -n 1:每次给函数传1行内容;-P 10:同时跑10个进程(可以根据服务器性能调整)
cat "$FILE_NAME" | xargs -n 1 -P 10 bash -c 'process_site "$@"' _

方法2:纯Bash后台进程+并发控制

如果不想用xargs,想自己手动控制并发数,可以用计数器配合wait -n来实现:

SECRET_KEY='zuhahaha'
FILE_NAME=""
case "$1" in
    "sma") FILE_NAME="sma.txt" ;;
    "smk") FILE_NAME="smk.txt" ;;
    "smp") FILE_NAME="smp.txt" ;;
    "sd") FILE_NAME="sd.txt" ;;
    *) echo "not in case !" && exit 1 ;;
esac

MAX_PROCS=10  # 最大并发数,按需调整
proc_count=0

save_log() {
    # 同样加锁保证日志写入的原子性
    flock -x output.log -c "
        printf '%s\n' \
            \"Header Code : $1\" \
            \"Executed at : $(date)\" \
            \"Response Body : $2\" \
            \"=====================================================================================================\" \
            \"\" >> output.log
    "
}

process_site() {
    local line="$1"
    local HTTP_RESPONSE=$(curl -L -s -w "HTTPSTATUS:%{http_code}\\n" -H "X-Gitlab-Event: Push Hook" -H "X-Gitlab-Token: $SECRET_KEY" --insecure "$line" 2>&1)
    local HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
    local HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
    save_log "$HTTP_STATUS" "$HTTP_BODY"
}

while IFS= read -r line; do
    # 启动后台进程处理当前站点
    process_site "$line" &
    proc_count=$((proc_count + 1))

    # 如果达到最大并发数,等待任意一个后台进程结束再继续
    if [ "$proc_count" -ge "$MAX_PROCS" ]; then
        wait -n  # 这个命令需要Bash 4.3及以上版本支持
        proc_count=$((proc_count - 1))
    fi
done < "$FILE_NAME"

# 等待所有剩余的后台进程完成
wait

方法3:用parallel工具(功能更强大)

如果你的系统能安装parallel(比如Debian/Ubuntu用apt install parallel),它比xargs更灵活,支持负载均衡、失败重试、进度显示等功能:

SECRET_KEY='zuhahaha'
FILE_NAME=""
case "$1" in
    "sma") FILE_NAME="sma.txt" ;;
    "smk") FILE_NAME="smk.txt" ;;
    "smp") FILE_NAME="smp.txt" ;;
    "sd") FILE_NAME="sd.txt" ;;
    *) echo "not in case !" && exit 1 ;;
esac

process_site() {
    local line="$1"
    local HTTP_RESPONSE=$(curl -L -s -w "HTTPSTATUS:%{http_code}\\n" -H "X-Gitlab-Event: Push Hook" -H "X-Gitlab-Token: $SECRET_KEY" --insecure "$line" 2>&1)
    local HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
    local HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
    
    flock -x output.log -c "
        printf '%s\n' \
            \"Header Code : $HTTP_STATUS\" \
            \"Executed at : $(date)\" \
            \"Response Body : $HTTP_BODY\" \
            \"=====================================================================================================\" \
            \"\" >> output.log
    "
}

export -f process_site
export SECRET_KEY

# -j 10:指定并发数;:::: 表示从文件读取输入
parallel -j 10 process_site :::: "$FILE_NAME"

关键注意点

  • 一定要用局部变量(local关键字),避免多个后台进程互相覆盖变量值;
  • 写日志的时候必须加锁(比如flock),否则多个进程同时写入会导致日志内容错乱;
  • 并发数不要设置得太高,不然可能会触发目标站点的限流,或者把自己的服务器资源占满。

内容的提问来源于stack exchange,提问作者0x00b0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:01:34