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

Bash新手求助:wget并行下载控制与fork资源报错解决

分析你的Bash脚本问题 & 并行下载的正确姿势

首先,你的脚本存在几个关键问题,直接或间接导致了fork: Resource temporarily unavailable错误以及其他潜在问题:

原脚本的核心问题

  1. 变量i未初始化:脚本开头没有给i赋值,第一次执行[ $i -le 10 ]时,$i是空字符串,会触发语法错误(比如[: -le: unary operator expected),后续逻辑彻底混乱,可能短时间内启动大量进程,直接触发系统进程数限制。
  2. URL拆分逻辑有隐患:for item in $list会把URL按空格/制表符拆分,如果你的URL包含空格、特殊字符,会被拆成多个无效参数,导致大量错误的wget进程被创建。
  3. wait的使用低效且粗暴:原脚本里的wait会等待所有后台进程结束后才启动下一批,不仅下载效率低,而且如果前一批进程没及时结束,后续逻辑可能继续创建新进程,最终突破系统进程上限。
  4. 日志冲突:多个后台wget默认会把日志写到同一个wget-log文件,互相覆盖后你根本无法排查单个下载的问题。

解决方法(针对4000个URL的并行需求)

下面推荐几种可靠的方案,既能精准控制并行数量,又能避免资源耗尽:

方案1:纯Bash脚本(持续保持指定并行数)

如果不想用额外工具,这个纯Bash脚本可以持续维持指定数量的下载进程(比批量等待的效率更高):

#!/bin/bash
max_parallel=10  # 可根据你的系统性能调整并行数
current_pids=()

# 用while read读取URL,避免空格/特殊字符拆分问题
while read -r url; do
    # 启动后台下载,日志输出到单独文件(避免覆盖)
    wget "$url" -o "download_$(date +%s%N).log" &
    current_pids+=($!)  # 记录进程ID

    # 如果达到最大并行数,等待任意一个进程结束
    if (( ${#current_pids[@]} >= max_parallel )); then
        wait -n  # Bash 4.3+支持,等待任意后台进程完成
        # 移除已完成的PID(简化处理,不影响核心逻辑)
        current_pids=("${current_pids[@]/$!}")
    fi
done <<< "$list"

# 等待剩余所有进程完成
wait "${current_pids[@]}"

如果你的Bash版本低于4.3(不支持wait -n),可以用这个兼容版本:

#!/bin/bash
max_parallel=10
current_pids=()

while read -r url; do
    wget "$url" -o "download_$(date +%s%N).log" &
    current_pids+=($!)

    if (( ${#current_pids[@]} >= max_parallel )); then
        wait "${current_pids[0]}"  # 等待第一个启动的进程完成
        current_pids=("${current_pids[@]:1}")  # 移除已完成的PID
    fi
done <<< "$list"

wait "${current_pids[@]}"

方案2:用xargs(系统自带,无需额外安装)

xargs是Linux默认自带的工具,简单高效,适合快速实现并行:

# 如果URL存在文件urls.txt(每行一个URL)
cat urls.txt | xargs -n 1 -P 10 wget -o wget_\$LINE.log

# 如果URL在变量$list里
echo "$list" | xargs -n 1 -P 10 wget -o wget_\$LINE.log
  • -n 1:每次给wget传递1个URL
  • -P 10:最多同时运行10个进程
  • wget_\$LINE.log:用行号命名日志文件,避免日志覆盖

方案3:用parallel(功能更强大,需手动安装)

parallel是专门的并行处理工具,对带特殊字符的URL支持更好,还能显示下载进度:

# 从文件读取URL
parallel -j 10 wget {} -o wget_{#}.log < urls.txt

# 从变量读取URL
echo "$list" | parallel -j 10 wget {} -o wget_{#}.log
  • -j 10:设置最大并行数
  • {}:代表每个输入的URL
  • {#}:代表输入的序号,用于命名日志文件

关于fork: Resource temporarily unavailable错误

这个错误本质是系统进程数上限被触发了——当短时间内创建的进程数量超过系统允许的最大值,系统无法分配更多资源,就会抛出这个错误。通过限制并行进程数(比如10-20个,根据你的服务器配置调整),就能完全避免这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:51:16