如何让findstr过滤“最后修改过的”文件?

时间:2015-11-13 14:17:44

标签: batch-file subdirectory findstr

我希望在存储在文件夹和所有子文件夹中的一组文件中捕获项目版本。

使用:

@echo off<br>
findstr /s "ProjectVersion" C:\srm2\reg\*.cpf > C:\RESULTS.txt

返回文件夹中的每个.cpf文件。

e.g。

C:\srm2\reg\132L\132L-20151111-150804.cpf:  <ProjectVersion Major="8" Minor="0" Build="22" Revision="20312" />
C:\srm2\reg\132L\132L.cpf:  <ProjectVersion Major="11" Minor="0" Build="0" Revision="20312" />
C:\srm2\reg\132L\132L18122014121012.cpf:  <ProjectVersion Major="8" Minor="0" Build="22" Revision="20312" />
C:\srm2\reg\132L\132L18122014121731.cpf:  <ProjectVersion Major="8" Minor="0" Build="22" Revision="20312" />
C:\srm2\reg\DANNY\DANNY-20151112-134545.cpf:  <ProjectVersion Major="11" Minor="0" Build="0" Revision="0" />
C:\srm2\reg\DANNY\DANNY-20151113-083530.cpf:  <ProjectVersion Major="11" Minor="0" Build="0" Revision="0" />
C:\srm2\reg\DANNY\DANNY-20151113-085621.cpf:  <ProjectVersion Major="11" Minor="0" Build="0" Revision="0" />
C:\srm2\reg\DANNY\DANNY-20151113-102018.cpf:  <ProjectVersion Major="11" Minor="0" Build="0" Revision="0" />
C:\srm2\reg\DANNY\DANNY.cpf:  <ProjectVersion Major="11" Minor="0" Build="0" Revision="0" />

如何过滤以仅返回每个子文件夹中的最后修改.cpf文件,因为某些文件夹包含同一文件的多个版本?

3 个答案:

答案 0 :(得分:1)

我在this post复制了答案,表明:&#34;你可以在Batch中编写一个递归算法,它可以精确控制你在每个嵌套子目录中所做的事情&#34; ,并稍微修改它以解决这个问题。该方法与其他答案相同:遍历树并在每个子文件夹中执行findstr,仅使用按上次修改日期排序的第一个文件;区别在于此过程是通过代码显式实现的,而不是通过for /Rdir /S命令实现的。

@echo off
setlocal EnableDelayedExpansion
cd C:\srm2\reg
call :treeProcess > C:\RESULTS.txt
goto :EOF


:treeProcess
set "output="
for /F "delims=" %%f in ('dir /B /A:-D /O:D *.cpf') do if not defined output (
   for /F "delims=" %%o in ('findstr "ProjectVersion" "%%f"') do set "output=!cd!\%%f: %%o"
)
if defined output echo !output!

rem Recursive call
for /D %%d in (*) do (
    cd %%d
    call :treeProcess
    cd ..
)

exit /b

答案 1 :(得分:0)

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION 
SET "sourcedir=U:\sourcedir"
SET "lastdir="
FOR /f "delims=" %%a IN ('DIR /s /b /a-d /o-d "%sourcedir%\*.bat" ') DO IF "!lastdir!" neq "%%~dpa" (
 FINDSTR /i "z" "%%a" >NUL
 IF NOT ERRORLEVEL 1 (
  ECHO(%%a
  SET "lastdir=%%~dpa"
 )
)

GOTO :EOF

您需要更改sourcedir的设置以适合您的具体情况。

您提供的一行代码根本不起作用。

此过程只生成基本形式的*.bat文件的目录列表(仅限完整文件名),但按反向日期顺序排序,不包括目录名。

报告在每个目录名中都是反向日期/时间顺序,因此任何目录的第一个匹配文件名都是最新文件。

如果目录名已更改,则执行findstr以找到所需的键串。如果找到,则errorlevel设置为0,因此它不是1 or greater所以文件名被回显,lastdir被设置为文件的目录名。

我只是使用了*.bat个文件,并在这些文件中搜索"z"进行测试。根据需要进行调整。

答案 2 :(得分:0)

您可以使用for /R /D递归遍历所有目录,然后使用dir /B /A:-D /O:-D返回按日期排序的文件列表(最新的第一个),并按for /F解析其输出第一项,因此您只枚举每个目录中的一个最新文件:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
> "C:\results.txt" (
    for /D /R %%D in ("C:\srm2\reg\*.*") do (
        call :SUB FILE LINE "%%~fD\*.cpf" "ProjectVersion"
        if defined LINE (
            echo/!FILE!:!LINE!
        )
    )
)
endlocal
exit /B

:SUB var_file var_line pattern string
set "%~1=" & set "%~2="
for /F "eol=| delims=" %%F in ('dir /B /A:-D /O:-D "%~3"') do (
    set "%~1=%%~fF"
    for /F "delims=" %%L in ('findstr /L "%~4" "%%~fF"') do (
        set "%~2=%%L"
        goto :EOF
    )
    goto :EOF
)

让我们首先看一下子程序:SUB,它打算每个目录执行一次。这需要4个参数:

  • %~1)用于保存检索文件路径的变量名称
  • %~2)用于保存与搜索字符串匹配的行的变量名称
  • %~3)获取文件排序列表的模式(最新的第一个)和
  • %~4)搜索字符串(预计每个文件最多出现一次)。

外部for /F循环解析命令dir /B /A:-D /O:-D "%~3"的输出,该命令实际构建了已排序的文件列表。循环想要遍历每一行,但由于最后有一个goto :EOF,循环在第一次迭代后被破坏,因此只处理第一个(因此也是最新的)列表项。此项的路径将分配给作为参数给出的第一个变量。如果没有项目与文件模式匹配,则变量保持为空。

内部for /F循环解析搜索命令findstr的输出。由于最多只出现一次搜索字符串,因此该循环最多只能迭代一次。如果找到匹配项,则将包含行分配给作为参数给出的第二个变量。如果未找到匹配项,则变量保持为空。

现在让我们看一下主程序。这将使用for /D /R以递归方式遍历给定的目录树,并遍历所有目录。对于每一个,调用子例程:SUB,传递以下参数:

  • 变量名FILE(将收到当前迭代目录中的最新文件),
  • 变量名LINE(将在文件中接收与搜索字符串匹配的行),
  • 附加了文件模式reg*.cpf的当前迭代目录,
  • 要求的搜索字符串ProjectVersion

最后,检查变量LINE是否空虚,如果不是,则echo输出包含文件路径,冒号和找到的行的行。

请注意,所有输出都会重定向到文件C:\results.txt

已经选择了使用子例程的方法,因为有一个goto命令用于在第一次迭代时终止某个for循环(参见上面的描述),但不是全部。 goto实际上会破坏它所放置的所有块上下文,甚至是所有嵌套的上下文。 for循环只是一种块命令,如if子句,或简单的分组命令()。使用子程序可以防止主程序块被子程序中放置的goto破坏。