此任务可以根据 XML 文件内容来完成,批处理文件包含一个命令行,其中包含四个 FOR 循环,批处理文件存储在包含要重命名文件的文件夹和 XML 的目录中文件annotations.xml。
@for /F "delims=" %%I in ('dir "%~dp0annotations.xml" /A-D /B /S 2^>nul') do for /F "tokens=2 delims=<>" %%J in ('%SystemRoot%\System32\findstr.exe /R /C:"<[^<>]*=\"New\" [^<>]*>.*,.*," "%%I"') do for /F "tokens=1,2 delims=, " %%K in ("%%J") do for /F "delims=" %%O in ('dir "%%~dpI" /A-D /B ^| %SystemRoot%\System32\findstr.exe /I /R "^[0123456789][0123456789][0123456789][0123456789]\.[a-z][0123456789][0123456789]$"') do ren "%%~dpI%%O" "%%K.%%L%%~xO"
更好的可读性是以下多行变体:
@echo off
for /F "delims=" %%I in ('dir "%~dp0annotations.xml" /A-D /B /S 2^>nul') do (
for /F "tokens=2 delims=<>" %%J in ('%SystemRoot%\System32\findstr.exe /R /C:"<[^<>]*=\"New\" [^<>]*>.*,.*," "%%I"') do (
for /F "tokens=1,2 delims=, " %%K in ("%%J") do (
for /F "delims=" %%O in ('dir "%%~dpI" /A-D /B ^| %SystemRoot%\System32\findstr.exe /I /R "^[0123456789][0123456789][0123456789][0123456789]\.[a-z][0123456789][0123456789]$"') do (
echo ren "%%~dpI%%O" "%%K.%%L%%~xO"
)
)
)
)
pause
注意: 上面的代码中有echo 到命令ren 的命令,只是输出文件重命名命令,而不是执行重命名命令。建议先运行这个多行批处理文件,以验证 XML 文件是否真的被正确处理,因此新文件名是否正确。
第一个 FOR 在后台执行另一个命令进程,其中%ComSpec% /c 和' 之间的命令行作为附加参数附加。所以执行是在 Windows 安装到 C:\Windows:
C:\Windows\System32\cmd.exe /c dir "C:\batch file directory\annotations.xml" /A-D /B /S 2>nul
DIR在后台搜索中由单独的命令进程执行
- 在批处理文件目录及其所有子目录中,因为选项
/S
- 由于选项
/A-D 仅用于文件(属性不是目录)
- 文件名
annotations.xml和
- 由于选项
/B 以完整路径输出仅找到的文件名,因为选项/S 用于处理后台命令进程的STDOUT(标准输出)。
DIR 可能找不到任何符合这些条件的文件。在这种情况下,DIR 将输出错误消息来处理 STDERR(标准错误),通过将其重定向到设备 NUL 来抑制该错误消息。
阅读有关Using command redirection operators 的Microsoft 文章,了解2>nul 的解释。重定向操作符 > 必须在 FOR 命令行上使用脱字符 ^ 转义,以便在 Windows 命令解释器在执行命令 FOR 之前处理此命令行时被解释为文字字符> 在后台启动的单独命令进程中执行嵌入的dir 命令行。
FOR 捕获输出以处理启动的后台命令进程的 STDOUT,并在启动后逐行处理此输出 cmd.exe 在完成执行 后关闭自身目录。
FOR默认会跳过空行,但这种情况下没有空行。
FOR 将默认将每个非空行拆分为子字符串,使用普通空格和水平制表符作为字符串分隔符,并将仅将第一个空格/制表符分隔的字符串分配给指定的循环变量。此处不需要这种行拆分行为,因为文件annotations.xml 的路径可能包含一个或多个空格。出于这个原因,选项 delims= 用于定义一个空的字符串分隔符列表,该列表禁用行拆分行为。
FOR 也会忽略第一个子字符串(在这种情况下是整行)以默认行尾字符 ; 开头的行。但是由 DIR 输出的完整限定文件名不能以分号开头。如果是 UNC 路径,文件的完整路径总是以驱动器号或反斜杠开头。因此,在这种情况下,FOR 不会忽略任何行。
第一个FOR遍历批处理文件目录及其子目录中的所有annotations.xml。
第二个 FOR 在后台再次运行另一个命令进程,以在当前 annotations.xml 上使用区分大小写的正则表达式执行 FINDSTR 以查找包含字符串的行="New" 在标记中的某个位置,此 XML 元素的值中至少有两个逗号分隔的字符串。
FINDSTR 找到的行输出由 FOR 捕获,并通过使用尖括号作为字符串分隔符将行拆分为子字符串进行处理,因为选项 delims=<>。由于tokens=2,仅将第二个尖括号分隔字符串(即FINDSTR 找到的XML 元素的值)分配给指定的循环变量J。
第三个FOR 处理XML 元素的值string,方法是使用逗号和普通空格作为delims=, 指定的字符串分隔符将其拆分。第一个子字符串分配给指定的循环变量K,由于tokens=1,2,第二个逗号/空格分隔的子字符串根据循环变量ASCII table分配给下一个循环变量L。
第四个FOR在单独的命令进程中运行DIR来查找当前annotations.xml目录下的所有文件。输出还经过FINDSTR过滤,最终输出到后台命令进程的STDOUT,只是那些没有文件路径的文件名正好是四位数字并且文件扩展名开始大小写- 对 ASCII 字母不敏感,接下来正好有两个数字。这种过滤可以在同一目录树上多次运行批处理文件,避免重命名已被先前批处理文件执行重命名的文件。
第四个FOR将没有文件路径的文件名一一处理,并分别运行想要的新名称的rename命令输出rename命令行。
要了解所使用的命令及其工作原理,请打开command prompt 窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。
-
call /? ... 解释 %~dp0 ... 参数 0 的驱动器和路径,即当前处理的批处理文件,即始终以反斜杠结尾的批处理文件的完整路径。
dir /?
echo /?
findstr /?
for /?
pause /?
ren /?