【问题标题】:How to rename files based on an XML content tag?如何根据 XML 内容标签重命名文件?
【发布时间】:2020-05-31 00:37:20
【问题描述】:

我是批处理脚本编写的新手,需要一些帮助。我有一个文件夹,其中有几个子文件夹,其中的文件如下所示:

  • 文件夹 0001
    • 0001.a00
    • 0001.a01
    • 0001.a02
    • 0001.a03
    • annotations.xml
  • 文件夹 0002
    • 0001.a00
    • 0001.a01
    • 0001.a02
    • 0001.a03
    • 0002.b00
    • 0002.b01
    • 0002.b02
    • 0002.b03
    • annotations.xml
  • 文件夹 0003
    • 0001.a00
    • 0001.a01
    • 0001.a02
    • 0001.a03
    • annotations.xml

每个文件夹都有annotations.xml。这个文件有各种 XML 标签。

我希望提取a1 标记之间的前两个详细信息,属性值为New,并重命名(或附加)文件*.[a-z][0-9][0-9],例如*.a00*.a01*.b01、@987654331 @等

<a1 L="New" T="xxx" etc..>ABC9876, 20200115-1630, 20200115-1730</a1>

我想将文件重命名为:

  • ABC9876.20200115-1630.a00
  • ABC9876.20200115-1630.a01
  • ABC9876.20200115-1630.a02

我使用了以下脚本:

call xpath.bat "annotations.xml" "//a1" >> renamed.txt

创建的文件renamed.txt 包含:

ABC9876, 20200115-1630, 20200115-1730*

我不知道如何继续重命名,包括循环所有文件夹并跳过那些已经完成的文件夹。如果我能得到一些想法和帮助,我会很高兴。

我还尝试了以下方法:

@echo off
setlocal EnableDelayedExpansion
for /f "tokens=1-2 delims=," %%a in (renamed.txt) do (
    echo ****************
    echo %%a echo %%b
    echo ****************
    set "new=%%a.%%b"
    set new=!new: =!
    echo !new!
    ren 0004.a03 !new!.mp3
)
pause

我只能重命名一个文件,但我不知道如何在保留现有扩展名的同时重命名所有文件。在上面的示例中,我尝试将其中之一重命名为 mp3

【问题讨论】:

  • for /f 循环中使用带括号的命令,或在for /f 循环中将renamed txt 作为带括号的命令读取。打开命令提示符窗口并输入 for /? 以了解如何最好地使用命令及其选项。
  • 我建议您选择一种可以使用本机方法读写 xml 文件的脚本语言。

标签: xml windows batch-file rename


【解决方案1】:

此任务可以根据 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&gt;nul 的解释。重定向操作符 &gt; 必须在 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=&lt;&gt;。由于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 /?

【讨论】:

  • 非常感谢 Mofi,我会检查并恢复
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-06
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 2014-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多