批处理脚本在带括号的文件名上失败

Dan*_*Lin 3 windows batch-file

我写了一个批处理脚本:

@echo off
set "zip=C:\Program Files\7-Zip\7z.exe"
for %%f in (%*) do (
    if exist "%%~f\" (
        "%zip%" a -tzip "%%~f.zip" "%%~f\*" -mx0
    ) else (
        "%zip%" a -tzip "%%~f.zip" %%f -mx0
    )
)
Run Code Online (Sandbox Code Playgroud)

当用户选择多个文件/文件夹并将它们拖到脚本文件上时,每个拖动的文件/文件夹都会被打包成一个 zip 文件。

在大多数情况下它工作正常。但是,如果被拖动的文件位于文件名包含括号的目录中,例如“myfolder(large)”,脚本将失败。

谁能说出导致此问题的原因以及如何解决?

asc*_*pfl 6

对于这个问题,我看到以下选项:

  1. ^使用临时变量转义括号:

    @echo off
    set "ZIP=C:\Program Files\7-Zip\7z.exe"
    set "ARGS=%*"
    set "ARGS=%ARGS:^=^^%"
    set "ARGS=%ARGS:&=^&%"
    set "ARGS=%ARGS:(=^(%"
    set "ARGS=%ARGS:)=^)%"
    for %%F in (%ARGS%) do (
        dir /A "%%~fF" | > nul 2>&1 findstr "DIR" && (
            "%ZIP%" a -tzip "%%~F.zip" "%%~F\*" -mx0
        ) || (
            "%ZIP%" a -tzip "%%~F.zip" "%%~fF" -mx0
        )
    )
    
    Run Code Online (Sandbox Code Playgroud)

    这种方法可以解决问题用括号()以及&^,但它不是针对有批处理脚本,如特殊意义的所有字符健壮<>|

  2. 为有问题的字符串启用和应用延迟扩展

    @echo off
    set "ZIP=C:\Program Files\7-Zip\7z.exe"
    set "ARGS=%*"
    setlocal EnableDelayedExpansion
    for %%F in (!ARGS!) do (
        endlocal
        dir /A "%%~fF" | > nul 2>&1 findstr "DIR" && (
            "%ZIP%" a -tzip "%%~F.zip" "%%~F\*" -mx0
        ) || (
            "%ZIP%" a -tzip "%%~F.zip" "%%~fF" -mx0
        )
        setlocal
    )
    endlocal
    
    Run Code Online (Sandbox Code Playgroud)

    我更喜欢这种方法,因为它可以解决所有特殊字符的问题。循环内部延迟扩展的切换(依赖于禁用它的 Windows 默认)是为了在%%F变量实例的扩展期间禁用它,否则会出现问题,以防字符串包含感叹号!。这里的问题是!在命令行上遇到的延迟扩展消耗。在执行延迟扩展之前,将for变量 like%%F扩展为其值;所以如果该%%F值包含 a!它就会消失 - 除非延迟扩展被禁用,其中!没有特别的意义。