Windows 上类似 rsync 的复制命令

Windows 上类似 rsync 的复制命令

总结

rsync --recursive --update我正在寻找一个与原始 Windows几乎完全相同的替代品。

细节

在 Windows 中,命令的工作原理如下:

输入:

  • 文件系统模式(仅限于传统的 Windows 类型:仅在最后一个分隔符后允许使用通配符的路径),可解析为文件和文件夹的集合
  • 文件夹路径(已存在)

效果:复制输入模式解析的每个项目:

  • 进入目标文件夹
  • 仅当它比同名目标项新时才执行。(文件夹会以递归方式评估文件的时间戳,就像使用robocopy /mir或 一样xcopy /d。)

进一步的要求:

  • 必须是单个“语句”(允许使用括号,但不允许使用分号)
  • 出错时返回非零,否则返回零
  • 仅使用原始 Windows 10(无 WSL、Cygwin)

如果还能满足以下条件,则可获得加分:

  • 对于文件夹项目,其工作方式类似于robocopy /purge(即)。rsync --delete

答案1

安装 Cygwin - 它有一个可用的 rsync 包,因此你可以获得 rsync.exe

多年来我一直用它在本地主机上同步磁盘到磁盘,同步到另一个 Windows 主机,以及同步到/从 ubuntu 主机 - 运行良好 :-)

路径必须像这样指定:/cygdrive/C/...

答案2

rsync --recursive --update --delete <FILE PATTERN> <DESTINATION PARENT DIR>/好的,在 Windows 上,不调用 Powershell(这会降低我应用程序的吞吐量)的单行等效代码是:

SETLOCAL EnableDelayedExpansion && FOR %%F IN (<FILE PATTERN>) DO (IF NOT EXIST %%F\NUL ( (xcopy %%F <DESTINATION PARENT DIR> /D /R /Y /I) || EXIT /B !ERRORLEVEL! ) ) && FOR /D %%D IN (<FILE PATTERN>) DO (IF EXIST %%D\NUL ( (robocopy %%D <DESTINATION PARENT DIR>\%%~nxD /MIR /PURGE || IF !ERRORLEVEL! LSS 8 cd. ) || EXIT /B !ERRORLEVEL!) )

为了解释这一点,我将把它分成几行并附上注释:

REM Stupidly, by default, Windows evaluates %variables% in loop blocks *before* the block executes.
REM   This line makes var evaluation instead act the way everyone would actually want and expect,
REM   although only when you use !variable! syntax.
SETLOCAL EnableDelayedExpansion

REM Stupidly, `FOR` with no params means: "expand wildcards only to files (not folders),
REM   and loop over the resulting list".
REM   But even this doesn't do what you expect, because folders *will* be retained
REM   in the expanded list -- the filtering *only* happens for wildcarded elements of the pattern.
REM   (See the note further below.)
REM Stupidly, Windows requires `%%` for loop vars in .bat files, but `%` at the command-line.
REM   (Be advised.)
FOR %%F IN (<FILE PATTERN>) DO (
    REM As mentioned above, the non-folders-only version of `FOR` *does* let folders through,
    REM   so we have to manually filter anway.
    REM The way in Windows (without calling Powershell) to check if a filename is
    REM   not a folder name is to do the weird construct below.
    IF NOT EXIST %%F\NUL (
        (xcopy %%F <DESTINATION PARENT DIR> /D /R /Y /I) || EXIT /B !ERRORLEVEL!
    )
REM `FOR /D` has the same unintuitive behavior described above for `FOR`,
REM   but switching the role of folders and non-folders.
) && FOR /D %%D IN (<FILE PATTERN>) DO (
    REM Ditto and vice-versa prev notes.
    IF EXIST %%D\NUL (
        REM `robocopy` returns exit codes 0-7 on success.
        REM   It's like Microsoft doesn't want its tools to be scriptable.
        REM   So we qualify the exit code.
        REM `CD.` is the best way I know to simulate the plain old POSIX `true`.
        (
            robocopy %%D <DESTINATION PARENT DIR>\%%~nxD /MIR /PURGE || IF !ERRORLEVEL! LSS 8 cd.
        ) || EXIT /B !ERRORLEVEL!
    )
)

就我而言,吞吐量并不比对 的调用更好,该调用powershell -Command "Copy-Item -Recurse -Force"进行了不必要的复制并产生了启动 Powershell 的开销,因为上面的替换代码xcopy对扩展文件模式中的每个项目分别调用。不,由于 Windows 命令行长度限制,我无法将扩展列表存储在 var 中并将其传递给 的单次调用xcopy。我们必须进行扩展,因为我们必须区分文件和文件夹,因为 的语法xcopy在文件和文件夹之间不一致, 的语法也是如此robocopy。在 2021 年,Windows 仍然缺少一个执行递归和仅更新的文件/文件夹无关的复制命令。所以,最后,我实际上无法做我想做的事情,我不得不强迫我的客户指定哪些模式用于文件,哪些用于文件夹。

相关内容