使用Windows ren命令从文件名中删除"!"符号

5

我有一堆文件,格式如下

filename-!#.ext

其中 # 是一个递增的数字,用于避免冲突。我想要将文件名中的 ! 删除,以便它读作

filename-#.ext

似乎我可以使用ren命令和通配符来完成这个任务,但是在实践中遇到了困难。我尝试运行以下命令:
ren *!?.ext *?.ext

我认为 * 应该匹配文件名的部分,接着是 !,然后是数字的 ?。然而,生成的文件名如下所示:
filename-!#.ext.ext

我无法确定原因。

文件名可能是动态的,但不会包含任何感叹号。有什么想法吗?

3个回答

6
我认为您需要使用一个小批处理文件来解决这个问题:
@echo off
    setlocal
    for %%a in (*!*.ext) do call :remove "%%~a"
    goto :eof

:remove
    set "FROM=%~1"
    set "TO=%FROM:!=%"
    ren "%FROM%" "%TO%"
    goto :eof

以上代码将针对所有包含感叹号和扩展名为“ext”的文件调用“remove”函数。该函数通过使用“%var:find = replace%”语法来确定新名称(“TO”),从原始名称(“FROM”)中移除任何感叹号(并用空字符串替换它)。
注意:
- 无法在 %%a%0 类型的变量中使用查找/替换,因此必须先将其分配给命名变量。 - 最初我尝试在“for”语句中进行“内联”操作(例如以“for ... ( 结尾的命令),但要做到这一点,您必须启用延迟扩展(因为您需要在循环中访问命名变量)。但是,延迟扩展使用“!”(而不是“%”)引用变量,并且这妨碍了我们试图删除的“!”符号。也许有一种方法可以做到这一点,但我没有发现。使用“call”会稍微慢一些,但除非您有成千上万个文件,否则不会显著影响速度。 - 您实际上不需要创建“TO”(您可以在“ren”命令行中执行替换),但我使用它是为了清晰明了。 - 这适用于所有带有感叹号的文件:它不检查其后面的位是否为数字。

1
好的答案。我试图使用delayedExpansion制作一个非常短的版本,以自动删除单个!,但是在重命名时,cmd忽略了所有的"并且“检测到”了一个变量覆盖了参数,例如ren "arg!var" "!arg2!"。所以我最终采用了内联调用版本,在这种情况下我更喜欢它,因为你不需要任何外部标签来跳转(而且代码更少)。 - timlg07
1
@timlg07 是的,我想我遇到了同样的问题。我得试着记住你的“call set”技巧(我以前见过,但显然不够频繁)。 - TripeHound
1
这也不错,但是它会在原始文件名中再次加倍 ^ 符号;您可以通过不使用参数 %~1 而在 for 循环中分配 set "FROM=%%~a" 并在子例程中读取变量 FROM 来避免这种情况... - aschipfl

5

我认为让rename选择文件不是一个好主意,而是应该用for循环来选择每个文件并执行重命名操作:

for %%F in (*!*) do (
    set "nxF=%%~nxF"
    call ren "%%nxF%%" "%%nxF:!=%%"
)

在这里你真的需要使用call而不是delayedExpansion,因为delayedExpansion会破坏重命名参数(因为它们包含!


2
你比我先完成了。但是你可以用少一个CALL的方式来实现。只需同时进行替换和重命名:call ren "%%F" "%%newF:!=%%" - Squashman
是的,我忘记在结尾处缩短它了。谢谢 ;) - timlg07
1
非常好的答案,但有一个小问题:原始文件名中的任何 ^ 都会变成两倍;为了避免这种情况,请使用另一个中间变量,如 set "oldF=%%~fF",并在 call 中使用 %%oldF%% 而不是 %%~fF - aschipfl
谁会在文件名中放置^?;D 感谢您的评论,我已更新我的代码。 - timlg07

4

根据您提供的信息,为了提供一些不同的东西,您可以让延迟扩展为您完成工作(因为它会为您删除不需要的感叹号)。!

@For %%A In ("*-!?.ext") Do @Set "_=%%A" & SetLocal EnableDelayedExpansion & Ren "!_!" "%%A" & EndLocal

您可能还可以使用嵌套的for循环来实现:

@For %%A In ("*-!?.ext") Do @For /F "Tokens=1*Delims=!" %%B In ("%%A") Do @Ren "%%A" "%%B%%C"

...并且从命令提示符:

For %A In ("*-!?.ext") Do @For /F "Tokens=1*Delims=!" %B In ("%A") Do @Ren "%A" "%B%C"

很棒的解决方案,我也打算这样做,但是忘记保存旧文件名了 ^^ - timlg07
2
非常好!我认为值得一提的是,这取决于每个文件名中只有一个感叹号的事实... - aschipfl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接