多FTP同目录文件下载脚本

一、总体概述

这两个文件是一对配套使用的 Windows 批处理(.bat)脚本 (以 .txt 形式保存),共同实现"从 3 台 FTP 服务器并行批量下载指定目录下所有文件"的功能:

文件 角色 核心职责
ftp_download_.bat 主脚本 配置参数、为每台服务器建目录、并行启动下载任务、等待并汇总结果
ftp_download_task.bat 辅助脚本 被主脚本按服务器逐台调用,负责"登录验证→列目录→逐个文件下载"

两者必须放在同一目录下运行,主脚本依赖辅助脚本,缺一不可。

bash 复制代码
@echo off
chcp 936 >nul
REM ============================================================
REM  FTP 单服务器下载辅助脚本(由主脚本并行调用)
REM  参数: %1=IP  %2=用户名  %3=密码  %4=远程目录  %5=保存根目录
REM  方式: 列目录(含登录验证) -> 逐个下载
REM  保存: 根目录\IP\远程目录层级(如 10.0.2.51\AAAA\BBBB\)
REM ============================================================
setlocal enabledelayedexpansion
set "IP=%~1"
set "FTP_USER=%~2"
set "FTP_PASS=%~3"
set "REMOTE_BASE=%~4"
set "SCRIPT_DIR=%~5"

REM 保存目录 = 根目录\IP + 远程路径层级(/ 转为 \)
set "DL_DIR=%SCRIPT_DIR%%IP%%REMOTE_BASE:/=\%"
if not exist "%DL_DIR%" mkdir "%DL_DIR%"

echo [%IP%] 开始连接 %REMOTE_BASE% ...
set "LIST_FILE=%DL_DIR%\_listing.tmp"
set "ERR_FILE=%DL_DIR%\_curl_err.tmp"

REM 1. 列目录(同时验证用户名密码)
curl.exe -sS --connect-timeout 15 --max-time 120 --ftp-pasv --user "%FTP_USER%:%FTP_PASS%" "ftp://%IP%%REMOTE_BASE%/" -o "%LIST_FILE%" 2>"%ERR_FILE%"
set "RC=%errorlevel%"
if not "%RC%"=="0" (
    set "ERRTXT="
    for /f "usebackq delims=" %%E in ("%ERR_FILE%") do set "ERRTXT=%%E"
    echo [%IP%] 连接失败,curl 错误码: %RC%
    if "%RC%"=="67" (
        echo [%IP%] 提示: 用户名或密码错误,请检查 FTP_USER / FTP_PASS 配置。
    ) else if "%RC%"=="7" (
        echo [%IP%] 提示: 无法连接服务器,请检查网络或 IP 地址是否可达。
    ) else if "%RC%"=="28" (
        echo [%IP%] 提示: 连接超时,请检查服务器状态。
    ) else (
        echo [%IP%] 提示: !ERRTXT!
    )
    del "%ERR_FILE%" >nul 2>nul
    exit /b %RC%
)
del "%ERR_FILE%" >nul 2>nul

if not exist "%LIST_FILE%" (
    echo [%IP%] 列目录失败
    exit /b 1
)

REM 统计文件数
set "COUNT=0"
for /f "usebackq tokens=* delims=" %%L in ("%LIST_FILE%") do (
    set "LINE=%%L"
    if not "!LINE:~0,1!"=="d" (
        set "FNAME="
        for %%F in (%%L) do set "FNAME=%%F"
        if defined FNAME set /a COUNT+=1
    )
)

if "%COUNT%"=="0" (
    echo [%IP%] 登录成功,但目录为空或无可下载文件。
    del "%LIST_FILE%" >nul 2>nul
    exit /b 0
)

echo [%IP%] 登录成功,共 %COUNT% 个文件,开始下载...
set "N=0"
set "FAIL=0"

REM 2. 逐行解析并下载(跳过目录行、跳过空行)
for /f "usebackq tokens=* delims=" %%L in ("%LIST_FILE%") do (
    set "LINE=%%L"
    if not "!LINE:~0,1!"=="d" (
        set "FNAME="
        for %%F in (%%L) do set "FNAME=%%F"
        if defined FNAME (
            set /a N+=1
            echo [%IP%] [!N!/%COUNT%] 下载中: !FNAME!
            curl.exe -sS --connect-timeout 15 --max-time 3600 --ftp-pasv --user "%FTP_USER%:%FTP_PASS%" "ftp://%IP%%REMOTE_BASE%/!FNAME!" -o "%DL_DIR%\!FNAME!" 2>"%ERR_FILE%"
            if !errorlevel! neq 0 (
                set /a FAIL+=1
                set "ERRTXT2="
                for /f "usebackq delims=" %%E in ("%ERR_FILE%") do set "ERRTXT2=%%E"
                echo [%IP%] 文件下载失败: !FNAME! 原因: !ERRTXT2!
            )
        )
    )
)

del "%LIST_FILE%" >nul 2>nul
del "%ERR_FILE%" >nul 2>nul
if "%FAIL%"=="0" (
    echo [%IP%] 全部下载完成: 共 %COUNT% 个文件, 失败 0 个。
) else (
    echo [%IP%] 下载完成: 共 %COUNT% 个文件, 失败 %FAIL% 个。
)
exit /b %FAIL%
bash 复制代码
@echo off
chcp 936 >nul
setlocal enabledelayedexpansion
title FTP batch download BBBB

REM ============================================================
REM  FTP 批量下载脚本(主脚本)
REM  功能:同时下载 3 台服务器 /AAAA/BBBB/ 下所有数据
REM  保存:分别存入本脚本同目录下
REM        10.0.2.51\AAAA\BBBB\
REM        10.0.3.51\AAAA\BBBB\
REM        10.0.5.51\AAAA\BBBB\
REM  用法:直接双击运行;如需改密码或日期,修改下方变量
REM  依赖:同目录需存在 ftp_download_task.bat 辅助脚本
REM ============================================================

set "FTP_USER=xxxx"
set "FTP_PASS=yyyy"
set "REMOTE_BASE=/AAAA/BBBB"
set "IP_LIST=10.0.2.51 10.0.3.51 10.0.5.51"
set "SCRIPT_DIR=%~dp0"

if not exist "%SCRIPT_DIR%ftp_download_task.bat" (
    echo [ERROR] 缺少辅助脚本 ftp_download_task.bat,请将其与本脚本放在同一目录。
    pause
    exit /b 1
)

echo 脚本目录: %SCRIPT_DIR%
echo 远程目录: %REMOTE_BASE%
echo 目标主机: %IP_LIST%
echo.

REM ---- 为每台服务器创建带远程路径层级的文件夹,并后台并行启动下载 ----
for %%I in (%IP_LIST%) do (
    if not exist "%SCRIPT_DIR%%%I%REMOTE_BASE%" mkdir "%SCRIPT_DIR%%%I%REMOTE_BASE%"
    start "FTP_DL_%%I" /min cmd /c ""%SCRIPT_DIR%ftp_download_task.bat" %%I "%FTP_USER%" "%FTP_PASS%" "%REMOTE_BASE%" "%SCRIPT_DIR%""
)

REM ---- 等待所有 curl 下载进程结束 ----
:waitloop
tasklist /fi "imagename eq curl.exe" 2>nul | find /i "curl.exe" >nul
if not errorlevel 1 (
    timeout /t 2 /nobreak >nul
    goto waitloop
)

echo.
echo ============ 全部下载任务结束 ============
for %%I in (%IP_LIST%) do (
    if exist "%SCRIPT_DIR%%%I%REMOTE_BASE%" (
        for /f %%C in ('dir /b "%SCRIPT_DIR%%%I%REMOTE_BASE%" 2^>nul ^| find /c /v ""') do echo [%%I] 已下载文件数: %%C
    )
)
pause
endlocal

二、文件 1:主脚本 ftp_download_.bat

1. 用途

同时从 3 台服务器(10.0.2.5110.0.3.5110.0.5.51)的远程目录 /AAAA/BBBB/ 下载所有数据,并按"IP\远程路径层级"分别保存到脚本所在目录下的子文件夹中(如 10.0.2.51\AAAA\BBBB\)。

2. 关键配置变量

  • FTP_USER=xxxxFTP_PASS=yyyy:FTP 账号密码(当前为占位符,使用前需替换为真实凭据)
  • REMOTE_BASE=/AAAA/BBBB:远程下载源目录
  • IP_LIST=10.0.2.51 10.0.3.51 10.0.5.51:3 台目标服务器 IP
  • SCRIPT_DIR=%~dp0:脚本自身所在目录(作为下载保存根目录)

3. 执行流程

  1. 初始化@echo off 关闭命令回显,chcp 936 切换 GBK 中文代码页,setlocal enabledelayedexpansion 开启延迟变量扩展,窗口标题设为 "FTP batch download BBBB"。
  2. 依赖检查 :检测同目录是否存在 ftp_download_task.bat,缺失则报错并退出(exit /b 1)。
  3. 建目录 + 并行启动for 循环遍历 3 个 IP,为每台创建本地保存目录(如 10.0.2.51\AAAA\BBBB),再用 start /min cmd /c最小化新窗口后台并行方式调用辅助脚本,传入 IP、用户名、密码、远程目录、保存根目录 5 个参数。
  4. 等待结束:waitloop 标签轮询 tasklist 检测 curl.exe 进程是否还在运行,每 2 秒检查一次,直到所有下载进程退出。
  5. 结果汇总 :用 dir /b | find /c /v 统计每个服务器目录下的已下载文件数并打印,最后 pause 暂停等待用户查看。

三、文件 2:辅助脚本 ftp_download_task.bat

1. 用途

单台服务器的下载执行单元,由主脚本并行调起 3 个实例。接收 5 个参数:%1=IP%2=用户名%3=密码%4=远程目录%5=保存根目录

2. 执行流程

  1. 准备保存目录 :将远程路径中的 / 转换为 \,拼出本地目录 根目录\IP\AAAA\BBBB,不存在则创建。
  2. 列目录(兼作登录验证) :用 curl.exe 以被动模式(--ftp-pasv)访问 ftp://IP/AAAA/BBBB/,连接超时 15 秒、总超时 120 秒,目录清单输出到临时文件 _listing.tmp,错误写入 _curl_err.tmp
  3. 错误处理 :若 curl 返回非 0,针对不同错误码给出中文诊断提示:
    • 67 → 用户名或密码错误
    • 7 → 无法连接服务器(网络/IP 不可达)
    • 28 → 连接超时
    • 其他 → 原样输出 curl 错误文本
  4. 统计文件数 :解析目录清单,跳过以 d 开头的目录行和空行,统计可下载文件个数;若为 0 则提示"目录为空"并正常退出。
  5. 逐个下载 :对每个文件再次调用 curl.exe 下载(单文件总超时放宽到 3600 秒),实时打印进度 [序号/总数] 下载中: 文件名;失败时累计失败数并打印原因。
  6. 收尾 :删除两个临时文件,汇总"共 N 个文件,失败 M 个",以失败数作为退出码(exit /b %FAIL%)。

四、两文件的关系与协作方式

复制代码
主脚本(配置+调度)
   │  for 每台服务器: start /min 后台窗口
   ├──> 辅助脚本实例1 (10.0.2.51)  ── curl 列目录→逐文件下载
   ├──> 辅助脚本实例2 (10.0.3.51)  ── 并行执行
   └──> 辅助脚本实例3 (10.0.5.51)  ── 并行执行
   │  轮询 curl.exe 进程直到全部结束
   └──> 汇总各目录文件数 → pause
  • 主脚本只管调度与汇总,不直接做 FTP 操作;真正的连接、验证、下载全部由辅助脚本完成。
  • 并行策略:3 台服务器同时下载,互不阻塞;主脚本通过监测 curl.exe 进程判断整体完成。

五、技术要点与注意事项

  1. 编码 :两脚本均执行 chcp 936,脚本文件需保存为 GBK/ANSI 编码,中文提示才能正常显示。
  2. 延迟扩展 :均使用 setlocal enabledelayedexpansion,循环内用 !变量! 取值,这是批处理循环中正确处理动态变量的关键。
  3. 依赖 curl :下载核心是 curl.exe(Win10 1803+ 自带),脚本本身不含 FTP 客户端程序。
  4. 只下载文件、不递归子目录 :辅助脚本会跳过目录行(以 d 开头),仅下载 /AAAA/BBBB/ 一级目录下的文件。
  5. 凭据为占位符 :当前 FTP_USER=xxxxFTP_PASS=yyyy 需在使用前修改为主脚本头部的真实账号密码;另建议注意脚本明文存密码的安全风险,避免随意外传。
  6. 健壮性设计:含依赖检查、登录失败诊断(区分密码错/网络不通/超时)、空目录提示、单文件失败不中断整体、最终成功/失败计数,容错较完善。

相关推荐
柒号华仔4 天前
「速通Shell」聚砖成墙,Shell函数封装之道
linux·ssh·bash
一水6 天前
Pi :内置四工具源码拆解——文件锁、变更快照与 bash 隔离
开发语言·chrome·ai·bash
北极糊的狐6 天前
阿里云宝塔报错bash tools/update.sh: No such file or directory 意思是:tools 整个目录直接丢失
阿里云·云计算·bash
xianyuCcCcCCCcc7 天前
Nginx 深度解析:从基础架构到反向代理与负载均衡实战全解
linux·运维·nginx·bash·负载均衡
大魔王爱学习14 天前
终端bash&zsh中实现基于前缀的历史命令搜索
linux·bash
酷可达拉斯15 天前
Linux操作系统-磁盘空间使用率100%如何处理?
linux·运维·服务器·云计算·bash
Nuanyt17 天前
Linux系统的 Shell 常见指令和常见知识点(以bash为主)
linux·运维·chrome·bash
小肝一下1 个月前
7. 库制作与原理
linux·c语言·操作系统·bash·shell·动静态库
德福危险1 个月前
从目录枚举到bash破壳漏洞、从流量抓包到组权限提权:靶机练习之symfonos3
开发语言·bash