使用CMD从包含它的所有文件中批量删除子字符串

问题描述 投票:0回答:1

我从旧备份中复制了文件,其中所有文件都附加了备份的时间戳,因此以前称为“background.jpg”的文件现在已在备份。我想从这些文件名中出现的位置删除所有这些时间戳,将文件名恢复到原来的样子。

我在这里发现了一个非常相似的问题:Using CMD on Windows to remove a certain substring from a directory of files

但是,我对这里的两个答案都感到困难。较短的一行脚本,我尝试像这样运行:

cmd /v:on /c "for /R %f in (* ^(2022_12_15 14_28_40 UTC^).*) do @set "nn=%~nf" & echo ren "%~ff" "!nn:~0,-26!%~xf""

(在上面的代码中,包含“echo”预览重命名(ren)操作而不实际执行它,而省略“echo”实际上执行一系列重命名。)我必须转义子字符串中的括号才能让它运行没有

.*) was unexpected at this time
错误。但它不能正常工作——它不是只关注指定子字符串的文件,而是将此操作应用于所有文件,这确实修复了所有带有子字符串的文件,但它也导致了一些问题,因为它擦除了文件名不带此子字符串且长度为 26 个字符或更短的文件。此外,还为顶级文件夹和其中的每个子文件夹添加了这些错误的重命名命令:

ren "C:\Users\[folder or subfolder]\(2022_12_15" ""
ren "C:\Users\[folder or subfolder]\14_28_40" ""

任何具有该名称的文件夹或子文件夹中都没有此类文件。在写这个问题时看这个,看起来 CMD 将此文件集解释为“*”AND“(2022_12_15”AND“14_28_40”AND“UTC).*”,这解释了它决定的文件集,但我不能找出如何让空格不以这种方式注册为分隔不同的标记,而是作为文件名规范本身的一部分(使用 ^ 转义不起作用)。有帮助吗?

我也尝试了 Mofi 的答案,但做了一些调整以适应我的特定子字符串:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "%~dp0* (2022_12_15 14_28_40 UTC).*" /A-D /B /S 2^>nul') do (
    set "FullFileName=%%I"
    set "FileNameOnly=%%~nI"
    set "FileExtension=%%~xI"
    setlocal EnableDelayedExpansion
    if /I "!FileNameOnly:~-26!" == " (2022_12_15 14_28_40 UTC)" ren "!FullFileName!" "!FileNameOnly:~0,-26!!FileExtension!"
    endlocal
)
endlocal

(我的文件看起来像上面一样,除了插入了很多注释作为注释来向自己解释发生了什么。)

但是使用上面的方法,我遇到了一些问题。当我像上面一样运行它时,我收到此错误:

. was unexpected at this time.

我认为这发生在“for”行上,因为上面的回声打印出来,但下面的回声却没有打印出来,尽管我认为我可能不明白回声在 Windows 批处理文件中的工作原理,因为:当我除了在“后面添加一个回声”之外什么都不改变时for ... do (" 行:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "%~dp0* (2022_12_15 14_28_40 UTC).*" /A-D /B /S 2^>nul') do (
    echo I1: %%I
    set "FullFileName=%%I"
    set "FileNameOnly=%%~nI"
    set "FileExtension=%%~xI"
    setlocal EnableDelayedExpansion
    if /I "!FileNameOnly:~-26!" == " (2022_12_15 14_28_40 UTC)" ren "!FullFileName!" "!FileNameOnly:~0,-26!!FileExtension!"
    endlocal
)
endlocal

我得到这个输出并且程序继续:

I1: C:\Users\[filepath redacted]\background (2022_12_15 14_28_40 UTC).jpg
The system cannot find the drive specified.
The system cannot find the drive specified.

我不明白为什么在这里添加回显会改变程序的行为。

当程序继续运行时,它不会对文件进行任何更改。我做了一些测试,似乎 IF 检查失败。但是,if 和重命名操作的逻辑似乎是合理的,因为如果我将三个变量(FullFileName、FileNameOnly 和 FileExtension)硬编码为特定文件的预期值:

    set "FullFileName=C:\Users\[filepath redacted]\background (2022_12_15 14_28_40 UTC).jpg"
    set "FileNameOnly=background (2022_12_15 14_28_40 UTC)"
    set "FileExtension=.jpg"

然后此脚本将按预期重命名文件。如果我像这样回显重命名操作,这就是我得到的:

    echo ren "!FullFileName!" "!FileNameOnly:~0,-26!!FileExtension!"

Prints:
    ren "C:\Users\[filepath redacted]\background (2022_12_15 14_28_40 UTC).jpg" "background.jpg"

此外,此文件夹及其子文件夹中有许多文件,但此脚本挑选出的文件(在我添加上述回显之后)正确地是文件名中包含此子字符串的唯一文件。

但是使用上面的设置命令不会像这些手动设置那样触发 IF。当我稍后在脚本中尝试打印 %%I 时,我再也没有得到第一次回显时打印出的值:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "%~dp0* (2022_12_15 14_28_40 UTC).*" /A-D /B /S') do (
    echo I1: %%I   <-- prints "I1: C:\Users\[filepath redacted]\background (2022_12_15 14_28_40 UTC).jpg"
    set "FullFileName=%%I"
    set "FileNameOnly=background (2022_12_15 14_28_40 UTC)"
    set "FileExtension=.jpg"
    echo I2: %%I   <-- prints "I2: %I"
    setlocal EnableDelayedExpansion
    if /I "!FileNameOnly:~-26!" == " (2022_12_15 14_28_40 UTC)" (
        :: The code goes into the IF here because of the hardcoded variables above.
        echo I3: %%I   <-- prints "I3: %I"
        echo ren "!FullFileName!" "!FileNameOnly:~0,-26!!FileExtension!"   <-- prints "ren "%I" "background.jpg"
    )
    endlocal
)
endlocal

我陷入困境,需要帮助。我不知道如何使用 for 循环变量

%%I
正确设置局部变量。我不明白为什么这个脚本不起作用,也不明白为什么插入回声会暂时修复它(但变量设置仍然不起作用)。这与我的子字符串中的括号有关吗?与空格?我只是希望获得一些有关如何修复单行代码以使其针对正确的文件集,或修复更复杂的批处理文件以使 for 和 set 行正常工作的帮助。

windows cmd substring batch-rename
1个回答
0
投票

我对这个问题有点快刀斩乱麻,走了这条路:

  1. 安装 Cygwin。
  2. 在此基础上编写 .sh 脚本:https://stackoverflow.com/a/27283349/22353749
  3. (需要确保换行符是Unix风格的,以便脚本正常运行。)
  4. 请注意,上面链接的脚本的一个问题是 sed 替换规范缺少引号,如果您要删除的子字符串有空格,这会导致问题。这样的事情对我有用:
find . -name "* (2022_12_15 14_28_40 UTC).*" -print0 | while read -d $'\0' file
do
    mv "file" "$(echo $file | sed 's/ (2022_12_15 14_28_40 UTC)//')"
done
© www.soinside.com 2019 - 2024. All rights reserved.