Windows 'dir' 命令:指定 '/s' 时按日期排序文件

Windows 'dir' command: sort files by date when '/s' is specified

目标: 我想使用批处理文件将具有特定扩展名的最新文件从 "source directory" 复制到 "destination directory"。最新的文件可能在源目录下的几个子目录下。

This question/answer is exactly what I want, however it does not seem to sort when the /s option is specified (as this comment would suggest):

FOR /F "delims=|" %%I IN ('DIR "K:\path\tp\source\dir\*.ext" /B /S /O:D') DO SET NewestFile=%%I
copy "%NewestFile%" "C:\path\to\destination\dir"

你可以自己测试一下DIR "K:\path\tp\source\dir\*.ext" /B /S /O:D,看看是不是没有排序。

我试过的:这个命令本身确实有效:DIR "K:\path\tp\source\dir\*.ext" /S /B | sort但我不知道如何在 for 循环中使用它(批处理文件在我可以确定错误之前退出 - 即使最后有 pause)。

有什么想法吗?

参见:dir docs

似乎一切正常。我相信您的问题出在原始函数的 "delims=|" 语句中。通过使用 "delims=",它所做的只是从循环输出中切断第一个 |。因为 | 不会在正常的 windows 文件路径中,所以完全不需要。尝试在语句中加入 "tokens=*"

我还建议使用 Set "String=" 而不是传统的 Set String=,因为在许多情况下空格可能是个问题。我在函数中更新了它。

批处理脚本:

@ECHO OFF

Rem | Configuration
Set "MainDirectory=C:\Folder1"
Set "FileExtension=*.txt"
Set "CopyDestination=C:\Folder2"

Rem | Search for the newest file in a directory/sub-directory
for /f "tokens=*" %%A in ('DIR "%MainDirectory%\%FileExtension%" /B /S /O:D') do (SET "NewestFile=%%A")

Rem | Copy file to a destination
copy "%NewestFile%" "%CopyDestination%"

goto :EOF

如果需要,您可以从批处理文件中调用 Powershell。在 Powershell.

的较新版本上可以缩短此代码
for /F "delims=" %%G IN ('powershell "gci -rec | where { ! $_.PSIsContainer } | sort LastWriteTime | select -last 1 | Select-Object fullname"') do set NewestFile=%%G

完整答案:

cd /d "K:\path\to\source\dir"
for /F "delims=" %%G IN ('powershell "gci -rec *.ext | where { ! $_.PSIsContainer } | sort LastWriteTime | select -last 1 | Select-Object fullname"') do set NewestFile=%%G
copy "%NewestFile%" "C:\path\to\dest\dir"

一个简单的解决方案可能是

@echo off
    setlocal enableextensions disabledelayedexpansion

    set "root=K:\path\tp\source\dir"
    set "mask=*.ext"

    for %%r in ("%root%\.") do for /f "tokens=2,*" %%a in ('
        robocopy "%%~fr" "%%~fr" "%mask%" /njh /njs /nc /ns /ts /s /ndl /nocopy /is /r:0 /w:0 /l
        ^| sort /r 
        ^| cmd /v /e /c"(set /p .=&echo(!.!)"
    ') do set "lastFile=%%b"

    echo Last file : "%lastFile%"

此代码使用 robocopy 生成带有时间戳前缀的文件列表(交换机只请求没有作业 header、没有作业摘要、没有文件 class、没有文件大小、时间戳、递归、无目录列表、无目录信息复制、包含相同文件、无重试、无等待、不复制仅生成列表)。

此时间戳前缀列表(UTF yyyy/mm/dd hh:mm:ss 最后一个文件写入)然后按相反顺序排序以获取第一行中的最后一个文件。该行是用一个单独的 cmd 实例检索的(这避免了 for /f 读取长数据列表的时间问题)所以 for /f 只读取一行。

由于 robocopy 行包含日期、时间和文件名,为了检索最后一个字段,我们请求 for /f 检索两个标记:一个包含小时(将存储在%%a) 和直到行尾的剩余文本(存储在 %%b

包含额外的 for %%r 只是为了防止使用 robocopy 时出现的常见问题。由于我们引用路径以防止出现空格问题,因此我们需要确保路径不以反斜杠结尾,反斜杠会转义路径的结束引号并使命令失败。