首页 > 解决方案 > 批处理脚本循环遍历文件夹,压缩文件夹中的每个文件并将其移动到不同位置的相应文件夹

问题描述

我有两组文件夹:

“C:\temp\eFS_manual_temp”包含一组子文件夹。另一个目录“C:\temp\eFS_manual\eFS”包含相同的子文件夹集。

我想使用下面的批处理脚本来压缩子文件夹中的所有文件,一次一个文件夹,并将压缩文件移动到具有相同文件夹结构的辅助位置:

SET SourceDir=C:\temp\eFS_manual\_temp
SET DestDir=C:\temp\eFS_manual\eFS

for /D %%a in ("%SourceDir%") do (

    CD /D "C:\Program Files\WinRAR"
    FOR /F "TOKENS=*" %%F IN ('DIR /B /A-D "%SourceDir%\%%a"') DO (
        RAR.exe a -ep "%DestDir%\%%a\%%~NF.zip" "%SourceDir%\%%a\%%~NXF"
    )

)

我收到以下错误:文件名、目录名或卷标语法不正确。

标签: batch-filecmd

解决方案


几行批处理文件代码包含几个错误。

第一个上线了for /D %%a in ("%SourceDir%") doFOR在不包含任何通配符的圆括号中的集合上/D忽略该选项。这可以在打开命令提示符窗口并运行时轻松看到:

for /D %I in ("%SystemRoot%") do @echo %I

此命令行仅打印"C:\Windows"括号中的字符串。

所以让我们运行这个带有通配符的命令行:

for /D %I in ("%SystemRoot%\*") do @echo %I

输出要好得多,因为列出的都是 Windows 系统目录中的所有非隐藏子目录。

这是执行批处理文件时出现错误消息的主要错误结果,并与下面描述的其他错误相结合。

命令行有多个错误

FOR /F "TOKENS=*" %%F IN ('DIR /B /A-D "%SourceDir%\%%a"') DO

%%a%SourceDir%将扩展为外部FOR命令行中子目录的完整限定名称是正确的。FOR分配给指定的循环变量只是在圆括号中设置的非隐藏目录的名称不包含路径,即仅for /D %I in (*) do @echo %I用于处理当前目录中的非隐藏子目录。但是在包含绝对或相对路径的括号中设置时,FOR将具有指定绝对或相对路径的目录名称分配给指定的循环变量。在命令提示符窗口中运行以下命令时可以看到此行为:

cd /D %SystemDrive%\
for /D %I in (.\*) do @echo %I
for /D %I in (%SystemDrive%\*) do @echo %I

RAR.exe在提取档案时自动创建整个目录树到指定的目标目录。但是目标目录在创建档案时必须已经存在。因此,建议确保目标目录中源目录的当前子目录也存在于目标目录中。

FOR在后台启动的单独命令进程中执行嵌入式DIRcmd.exe /C命令行,并捕获所有行输出以通过DIR处理此单独命令进程的STDOUT在这种情况下, DIR仅输出具有所有文件的文件扩展名的文件名,包括在指定目录中找到的具有隐藏属性集的文件。

FOR会跳过捕获的空行,并且默认以;because of开头的行也是如此。导致从捕获的行中删除前导空格/制表符,如果还有一些东西,剩余的行将分配给指定的循环变量,以便由FOR循环体中的命令处理。如果文件名以空格或分号开头,则该行为不好。更好的做法是完全关闭行拆分行为并将完整的文件名分配给指定的循环变量。eol=;tokens=*delims=

但即使修复了所有这些错误,仍然存在问题。控制台应用程序手册是WinRAR程序文件夹中Rar.exe的文本文件。它在顶部清楚地解释了仅支持RAR存档。它不支持ZIP等其他存档类型作为支持。因此不能用于创建 ZIP 存档文件。Rar.txtRar.exeWinRAR.exeRar.exe

示例使开发人员的生活更轻松,因此让我们从一个示例开始:

源目录C:\temp\eFS_manual\_temp包含以下目录和文件:

  • 子文件夹 1
    •    文件 1.txt
    • ;评论和报告!它.自述文件
    • 文件 2.csv
  • 子文件夹 2
    • .htaccess
    • 再来一份 %file.txt

对于使用批处理文件进行处理的文件名确实很难看,因为

  • 以空格开头的文件名;
  • 以分号开头的文件名;
  • 包含感叹号的文件名;
  • 包含百分号的文件名;
  • 文件名以点开头并且没有更多的点。

所有文件和目录都没有设置隐藏属性。

目标目录C:\temp\eFS_manual\eFS应该包含在批处理文件执行之后:

  • 子文件夹 1
    •    文件 1.zip
    • ;评论和报告!它.zip
    • 文件 2.zip
  • 子文件夹 2
    • .htaccess.zip
    • 再来一份 %file.zip

ZIP 文件当然是真正的 ZIP 压缩存档文件,每个压缩文件只包含一个没有路径的压缩文件。

这个目标可以通过以下方式实现:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\temp\eFS_manual\_temp"
set "DestDir=C:\temp\eFS_manual\eFS"

for /D %%I in ("%SourceDir%\*") do (
    md "%DestDir%\%%~nxI" 2>nul
    for %%J in ("%%I\*") do (
        if not "%%~nJ" == "" (
            "%ProgramFiles%\WinRAR\WinRAR.exe" a -afzip -cfg- -ep -ibck -inul -m5 -y -- "%DestDir%\%%~nxI\%%~nJ.zip" "%%J"
        ) else (
            "%ProgramFiles%\WinRAR\WinRAR.exe" a -afzip -cfg- -ep -ibck -inul -m5 -y -- "%DestDir%\%%~nxI\%%~xJ.zip" "%%J"
        )
    )
)

endlocal

可以通过将第一行更改为@echo on并从命令提示符窗口中运行批处理文件来了解此批处理文件的工作原理,因为在这种情况下,Windows 命令处理器在预处理/解析后输出每一行,如Windows 命令解释器如何 ( CMD.EXE) 解析脚本?在执行命令行之前。

如果源目录中也有目录或文件具有隐藏属性集,也应由该批处理文件处理,则有必要使用命令DIR 。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\temp\eFS_manual\_temp"
set "DestDir=C:\temp\eFS_manual\eFS"

for /F "eol=| delims=" %%I in ('dir "%SourceDir%\*" /AD /B 2^>nul') do (
    md "%DestDir%\%%I" 2>nul
    for /F "eol=| delims=" %%J in ('dir "%SourceDir%\%%I\*" /A-D /B 2^>nul') do (
        if not "%%~nJ" == "" (
            "%ProgramFiles%\WinRAR\WinRAR.exe" a -afzip -cfg- -ep -ibck -inul -m5 -y -- "%DestDir%\%%I\%%~nJ.zip" "%SourceDir%\%%I\%%J"
        ) else (
            "%ProgramFiles%\WinRAR\WinRAR.exe" a -afzip -cfg- -ep -ibck -inul -m5 -y -- "%DestDir%\%%I\%%~xJ.zip" "%SourceDir%\%%I\%%J"
        )
    )
)

endlocal

此批处理文件考虑到带有选项和不带选项的DIR输出目录和文件名始终没有路径。/B/S

请阅读有关使用命令重定向运算符的Microsoft 文章以了解2>nul. 当 Windows 命令解释器在执行命令FOR之前在后台启动的单独命令进程中执行嵌入式命令行时,重定向操作符>必须^FOR命令行上使用脱字符进行转义以被解释为文字字符。dir

WinRAR命令行是由

  • 启动WinRAR ,
  • 从最后一个菜单打开通过单击第一个菜单项帮助主题来帮助帮助,
  • 在选项卡内容上导航到列表项命令行模式
  • 单击 [+] 扩展此列表项,
  • 单击子列表项命令行语法并在顶部复制粗体作为命令行模板,
  • 通过单击 [+] 子列表项命令并单击按字母顺序排列的命令列表并选择a作为用于此任务的命令,在列表中向左展开,
  • 通过单击 [+] 子列表项Switches并单击Alphabetic 开关列表并选择适合此任务的开关,在列表中向左展开,
  • 最后使用正确的字符串作为存档文件名和要存档的文件名。

要了解使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • if /?
  • md /?
  • set /?
  • setlocal /?

推荐阅读