批处理脚本遍历文件夹,将文件夹中的每个文件压缩,然后将其移动到其他位置的相应文件夹中

时间:2018-10-19 11:29:06

标签: batch-file cmd

我有两组文件夹:

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

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

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"
    )

)

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

2 个答案:

答案 0 :(得分:0)

对我而言,最棘手的部分是将新的目录路径内置到$NewDir中。完成此操作后,使用Compress-Archive制作.zip格式的存档非常容易。假设您要在源目录不包含任何文件的情况下创建空目录。

由于您需要一个.zip存档文件,因此我使用了Compress-Archive。如果您要使用其他工具(rar.exe或7z.exe),可以对其进行一些更改来代替它。

$SourceDir = 'C:\src\t'
$DestDir = 'C:\src\tarch'

Get-ChildItem -Recurse -Directory -Path $SourceDir |
    ForEach-Object {
        $SubName = $_.FullName.Replace($SourceDir, '')
        $NewDir = $DestDir + $SubName
        if (-not (Test-Path -Path $NewDir)) { New-Item -ItemType Directory -Path $NewDir }

        $files = Get-ChildItem -File -Path $_.FullName
        if ($files.Count -gt 0) {
            $files | Compress-Archive -DestinationPath $NewDir\archcopy.zip
        }
    }

要在.bat文件脚本中运行此命令,请将上面的代码放入Archive-eFS_manual.ps1之类的文件中。使用以下命令运行它:

powershell -NoProfile -File .\Archive-eFS_manual.ps1

答案 1 :(得分:0)

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

第一个在线for /D %%a in ("%SourceDir%") do上。 FOR 在不包含任何通配符的圆括号中对选项/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将扩展为外部 FOR 命令行中%SourceDir%中子目录的完全限定名称。 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 在以cmd.exe /C为背景的单独命令过程中执行嵌入式 DIR 命令行,并捕获所有输出以处理 STDOUT < / strong>,由 DIR 完成。 DIR 在这种情况下仅输出所有文件的文件扩展名,包括在指定目录中找到具有隐藏属性集的文件。

捕获的空行被 FOR 跳过,由于默认为;,因此以eol=;开头的行将被跳过。 tokens=*会导致从捕获的行中删除前导空格/制表符,如果还有剩余的内容,则剩余的行将分配给指定的循环变量,以供正文中的命令处理> FOR 循环。如果文件名以空格或分号开头,则该行为不好。最好使用delims=来完全关闭行拆分行为,并为指定的循环变量分配完整的文件名。

但是即使修复了所有这些错误,仍然会有问题。控制台应用程序Rar.exe的手册是 WinRAR 程序文件文件夹中的文本文件Rar.txt。它清楚地说明了Rar.exe仅支持 RAR 存档。它不支持其他存档类型,例如WinRAR.exe支持的 ZIP 。因此Rar.exe不能用于创建ZIP存档文件。

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

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

  • 子文件夹1
    • 文件1.txt
    • ;评论和报告! it.readme
    • 文件2.csv
  • 子文件夹2
    • .htaccess
    • 再加上%file.txt

由于批处理文件的处理,这真是丑陋的文件名,因为

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

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

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

  • 子文件夹1
    • 文件1.zip
    • ;评论和报告! it.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命令处理器会按照上述说明在预处理/解析后输出每一行在执行命令行之前,在How does the Windows Command Interpreter (CMD.EXE) parse scripts?处。

如果源目录中还存在具有隐藏属性集的目录或文件,则必须使用命令 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)始终输出目录和文件名而没有路径。

请阅读有关Using Command Redirection Operators的Microsoft文章,以获取2>nul的解释。当Windows命令解释器在执行命令之前处理此命令行时,重定向操作符>必须在 FOR 命令行上使用脱字符号^进行转义,才能被解释为文字字符。 FOR ,它将在后台启动的单独命令进程中执行嵌入式dir命令行。

WinRAR 命令行由

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

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

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