【问题标题】:How to copy a file depending on file size comparison?如何根据文件大小比较复制文件?
【发布时间】:2018-05-26 11:28:27
【问题描述】:

有子目录 SF 包含名称相同但文件大小不同 ( 我想将文件从S 复制到F,如果S 的文件小于F 的文件。

FOR /R %%F IN ( >>THE_FILES_IN_S<< ) DO (
    set fileS="S/%%~nF"
    FOR /F "usebackq" %%A IN ('%fileS%') DO set sizeS=%%~zA
    set fileF="F/%%~nF"
    FOR /F "usebackq" %%A IN ('%fileF%') DO set sizeF=%%~zA
    if %sizeS% LSS %sizeF% (copy /V /Y %fileS% %fileF%)
)

上面的代码 不起作用,因为&gt;&gt;THE_FILES_IN_S&lt;&lt; 是伪代码。

什么是正确的表达方式?

还有其他错误吗(正确的形式是什么)?

【问题讨论】:

  • 通常你可以在for 中使用.* 来浏览当前目录中的所有文件,但我不确定它是否适用于你的情况
  • 1 000 000+ 回答了关于ss64.com/nt/delayedexpansion.html的问题
  • @JosefZ:我不知道“默认情况下扩展只会发生一次”。感谢您提供链接!

标签: windows batch-file command-line


【解决方案1】:

不适用约 2GB 的 32 位有符号整数大小限制
当比较字符串中的数字时,用零填充到相等的长度。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BaseFolder=C:\Temp"

for %%S in ("%BaseFolder%\S\*") do (
    if exist "%BaseFolder%\F\%%~nxS" (
        for %%F in ("%BaseFolder%\F\%%~nxS"
            ) do Call :Check %%~zS %%~zF || copy /Y "%%S" "%%F" >nul
    )
)
endlocal
Goto :Eof
:Check
Set "S=00000000000000000000%1"
Set "F=00000000000000000000%2"
If %S:~-20% LSS %F:~-20% exit /B 1

上述批处理通过将大小传递给子例程并比较具有 20 位小数的字符串来避免延迟扩展,在此失败条件下复制的结果较少时返回错误级别。

【讨论】:

    【解决方案2】:

    在命令块中定义/修改并在同一命令块中引用的环境变量的使用需要使用delayed expansion。在命令提示符窗口set /? 中运行命令SET 输出的帮助解释了延迟扩展在IFFOR 示例中的用法。

    最好的方法是通过直接使用循环变量而不是将它们的值分配给环境变量,然后在以( 开头并以匹配) 结尾的命令块中引用环境变量的值,从而避免使用延迟扩展。

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    set "BaseFolder=C:\Temp"
    
    for %%S in ("%BaseFolder%\S\*") do (
        if exist "%BaseFolder%\F\%%~nxS" (
            for %%F in ("%BaseFolder%\F\%%~nxS") do (
                if %%~zS LSS %%~zF copy /Y "%%S" "%%F" >nul
            )
        )
    )
    
    endlocal
    

    将第三行中的C:\Temp 替换为基本文件夹的真实路径。如果批处理文件存储在基本文件夹中,则第三行可以替换为:

    rem Base folder is the directory containing the batch file.
    set "BaseFolder=%~dp0"
    rem Remove the backslash at end from batch file path.
    set "BaseFolder=%BaseFolder:~0,-1%"
    

    外部FOR 搜索与通配符模式*(任何名称)匹配的基本文件夹的子目录S 中的任何非隐藏文件,并将完整的限定文件名分配给循环变量@987654330 @。

    如果在基本文件夹的子目录F 中也存在具有相同文件名和文件扩展名的文件,则再执行一个 FOR 循环,该循环仅分配当前文件的已知全限定文件名在子目录F 中循环变量F 然后再运行一个IF比较。

    内部 IF 与 32 位有符号整数比较两个文件的文件大小,并将子目录 S 中的较小文件复制到子目录 F 并抑制成功消息输出由 COPY 通过将其重定向到设备 NUL 来处理 STDOUT

    请注意,此批处理文件仅适用于小于 2 GiB 的文件,因为 Windows 命令处理器在处理整数值时存在 32 位有符号整数限制。

    上面的整个批处理代码也可以写成一个命令行:

    @for %%S in ("C:\Temp\S\*") do @if exist "C:\Temp\F\%%~nxS" for %%F in ("C:\Temp\F\%%~nxS") do @if %%~zS LSS %%~zF copy /Y "%%S" "%%F" >nul
    

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

    • call /? ... 解释 %~dp0(参数 0 的驱动器和路径 - 批处理文件)
    • copy /?
    • echo /?
    • endlocal /? ... 此处并不真正需要,可以将其删除。
    • for /?
    • if /?
    • rem /?
    • set /?
    • setlocal /? ... 此处并不真正需要,可以将其删除。

    【讨论】:

    • 谢谢,接受了,也会投票赞成,但还没有必要的声誉。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多