【问题标题】:rename files with certain characters with cmd使用 cmd 重命名具有某些字符的文件
【发布时间】:2019-04-26 07:20:18
【问题描述】:

我没有找到关于这个特殊需求的其他帖子。 示例:

火影忍者 NA - 480p.mp4

我想删除“NA” 所以会是

火影忍者 - 480p.mp4

我试过了

for /f "tokens=1*delims=NA" %%a in ('dir /b "*NA*.*"') do ren "%%aNA%%b" "%%a%%~xb"

但输出是

火影忍者.mp4

不仅“- 480p”不见了,而且火影忍者和.mp4之间还有一个空格

【问题讨论】:

  • 您可以为此使用字符串替换,但第一个不区分大小写,第二个需要普通字符串(并且在代码块中还延迟扩展),第三个您需要上下文,否则 @987654322 @ from Naruto 也将被替换。

标签: windows cmd rename


【解决方案1】:

有多种可能的解决方案。

只要没有文件名包含一个或多个!,第一个就有效:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
for %%I in ("* NA -*") do (
    set "FileName=%%~nI"
    ren "%%I" "!FileName:NA -=-!%%~xI"
)
endlocal

当前文件的文件名被分配给环境变量FileName,没有文件扩展名。在执行命令 REN 之前,Windows 命令处理器会执行字符串替换,以将不区分大小写的所有出现的 NA - 替换为文件名中的 -,以删除文件名中不需要的部分.

问题是set "FileName=%%~nI" 行导致%%~nI 引用的文件名包含一个或多个感叹号,Windows 命令处理器在将%%~nI 替换为当前文件的文件名后再次解析此命令行并解释每个 ! 作为引用的环境变量的开始/结束延迟。

第二种解决方案也适用于带有感叹号的文件名:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for %%I in ("* NA -*") do (
    set "FileName=%%~nI"
    setlocal EnableDelayedExpansion
    ren "%%I" "!FileName:NA -=-!%%~xI"
    endlocal
)
endlocal

将当前文件的文件名分配给环境变量FileName 是在禁用延迟环境变量扩展的情况下完成的,因此! 被解释为文字字符。然后启用delayed expansion,以便在重命名文件和恢复以前的本地环境之前能够使用字符串替换。

Naruto NA - 480p.mp4 重命名为Naruto - 480p.mp4 的另一种解决方案是:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir "* NA -*" /A-D-H /B 2^>nul') do for /F "eol=| tokens=1,2* delims= " %%A in ("%%~nxI") do ren "%%I" "%%A %%C"
endlocal

带有选项/F 的外部FOR 和用直单引号括起来的圆括号中的字符串在后台以cmd.exe /C 开头的单独命令进程中运行:

dir "* NA -*" /A-D-H /B 2>nul

DIR 在当前目录中搜索

  • 由于选项 /A-D-H 导致的非隐藏文件(属性不是目录且未隐藏)
  • 匹配通配符模式* NA -*
  • 由于选项/B,以裸格式逐行处理STDOUT仅带有文件扩展名的文件名而没有路径。

DIR 还可以在未找到与通配符模式匹配的非隐藏文件的情况下输出错误消息以处理 STDERR。此错误消息使用 2>nul 重定向到设备 NUL 以抑制它。

阅读有关Using Command Redirection Operators 的Microsoft 文章,了解2>nul 的解释。重定向运算符 > 必须在 FOR 命令行上使用插入字符 ^ 进行转义,以便在 Windows 命令解释器在执行命令 FOR 之前处理此命令行时解释为文字字符> 在后台启动的单独命令进程中执行嵌入的dir 命令行。

FOR 捕获所有行输出以处理已启动命令进程的 STDOUT,并在启动 cmd.exe 终止后处理这些行。

FOR 会忽略空行,此处不会出现。

; 开头的行也会被 FOR 忽略,因为它是选项行尾的默认设置。文件名可以以分号开头。出于这个原因,eol=| 用于将竖线定义为文件名不能包含的行尾字符。

FOR 将使用普通空格和水平制表符作为字符串分隔符将行拆分为子字符串,并将仅将第一个空格/制表符分隔的字符串分配给指定的循环变量I。由于文件名包含多个空格,因此此处不需要此行为。因此delims=用于定义一个空的分隔符列表来关闭命令FOR的这种字符串拆分行为。

使用使用的选项完全分配给指定循环变量I 的当前文件名,即使以; 或一个或多个空格开头,也会被内部FOR 处理为字符串。

eol=| 在内部 FOR 上再次使用,以避免不忽略以; 开头的文件名。对于内部 FOR,需要在空格上拆分文件名字符串,因此选项 delims=  用于明确将空格定义为分隔符。对于Naruto NA - 480p.mp4,文件名字符串应在所有出现的一个或多个空格处分成三部分:

  1. 第一个子字符串(令牌)Naruto 应分配给指定的循环变量A
  2. 第二个子字符串NA应该根据ASCII table分配给下一个循环变量B
  3. 在第二个空格分隔的子字符串之后的所有空格之后,字符串的其余部分应分配给下一个但一个循环变量C,在本示例中为- 480p.mp4

这可以通过选项tokens=1,2* 来实现。

REN命令中,第二个子字符串被省略,因此新文件名为Naruto - 480p.mp4

当然,这第三个解决方案不适用于名称为 Naruto Uzumaki NA - 480p.mp4 的文件,因为新名称将是 Naruto NA - 480p.mp4,因为在这种情况下,第二个空格分隔的子字符串是 Uzumaki 而不是 NA

要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • ren /?
  • set /?
  • setlocal /?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-05
    • 2014-11-29
    • 1970-01-01
    • 2017-07-25
    • 2021-04-19
    • 2015-02-05
    • 2014-07-17
    相关资源
    最近更新 更多