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
时出现的常见问题。由于我们引用路径以防止出现空格问题,因此我们需要确保路径不以反斜杠结尾,反斜杠会转义路径的结束引号并使命令失败。
目标: 我想使用批处理文件将具有特定扩展名的最新文件从 "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
时出现的常见问题。由于我们引用路径以防止出现空格问题,因此我们需要确保路径不以反斜杠结尾,反斜杠会转义路径的结束引号并使命令失败。