如何用目录中多个文件的字符串替换文件名中的第一个space?

How to replace just first space in file name by a string on multiple files in a directory?

有谁知道如何用文件名前 8 个字符后的 _TEMP- 之类的文本替换文件名中的第一个 space?

我也希望写一个批处理文件,可以更改具有相似文件名结构的目录中的多个文件。

例如:

之前: 12345678 Hello World.txt

之后: 12345678_TEMP-Hello World.txt

这是一个简单的代码,演示了 FOR 用于此任务的用法:

@echo off
set "FileName=12345678 Hello World.txt"
for /F "tokens=1*" %%I in ("%FileName%") do echo ren "%FileName%" "%%I_TEMP-%%J"
set "FileName="
echo/
pause

此处文件名分配给环境变量。

带选项 /F 的命令 FOR 使用默认分隔符 space 和水平制表符将双引号中指定的文件名字符串拆分为子字符串。

tokens=1*定义的是首先space/tab定界字符串赋值给指定的循环变量I。星号负责在第一个字符串之后不在 spaces/tabs 上进一步拆分,而是将第一个字符串之后 space(s)/tab(s) 之后的所有内容分配给下一个循环变量,这是根据 ASCII table循环变量J。因此,对于此示例,I 被分配 12345678 并且 J 被分配 Hello World.txt

要执行的命令在这里 ECHO 打印用于重命名文件的命令行,如果没有 echo.

另一个批处理代码,它重命名当前目录中所有非隐藏文件,文件名中的 space 文件名中不包含 _TEMP-

@echo off
for /F "eol=| delims=" %%# in ('dir "* *" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /V /C:_TEMP- 2^>nul') do (
    for /F "tokens=1*" %%I in ("%%#") do ren "%%#" "%%I_TEMP-%%J"
)

外部 FOR 在后台命令行中以 cmd.exe /C 启动的单独命令进程中执行:

dir "* *" /A-D-H /B 2>nul | C:\Windows\System32\findstr.exe /L /V /C:_TEMP- 2>nul

DIR 在当前目录中搜索,因为 /A-D-H(属性不是目录且未隐藏)仅针对与通配符模式匹配的非隐藏文件 * * 和由于 /B (裸格式),只输出找到的文件名。如果没有文件符合这些条件,则通过将写入处理 STDERR 的错误消息重定向到设备 NUL.[=59 来抑制错误消息=]

DIR处理STDOUT的文件名被重定向到命令的STDIN FINDSTR 在文件名列表 case-sensitive 中搜索字符串 _TEMP-。但是输出的不是包含这个字符串的行,而是因为/V的反转结果。所以输出是由 FINDSTR 来处理 STDOUT 包含字符串 _TEMP- 的所有行 notFINDSTR 为处理 STDERR 可能输出的错误消息通过将其重定向到设备 NUL.

外层的FOR捕获后台命令进程的输出到STDOUT,然后逐行处理捕获的输出。处理捕获的文件名列表在这里非常重要,因为在当前目录中找到要修改的文件是由 FOR 循环内的命令重命名的。否则,在使用 FOR 本身查找与通配符模式 * * 匹配的文件时,可能会发生多次处理重命名文件或由于当前目录中的文件列表而跳过某些文件在循环执行期间发生变化。

FOR 始终忽略空行,但文件名列表不包含空行。

for /F 默认情况下也会忽略以分号开头的行。通过指定 eol=| 跳过以竖线开头的行,可以更改此行为。文件名可以以分号开头,但文件名不能包含竖线。所以确保不跳过任何带有 eol=|.

的文件名 使用默认选项的

for /F 会在 spaces/tabs 上拆分一行(文件名),并且只会将第一个子字符串分配给指定的循环变量 #。这种行为在这里并不好,因为文件重命名任务需要 DIR 的过滤输出的完整文件名。出于这个原因,delims= 用于指定一个空的分隔符列表,导致不会将行(文件名)拆分为子字符串(标记)。

可能是某个文件的命名方式如12345678 Hello World.txt,文件名中有多个space串联。这就是首先将 DIR 在当前目录中找到的完整文件名分配给循环变量 # 的原因。

文件名如上所述被分成两个子字符串,然后重命名,如果当前目录中还没有具有新名称的文件或文件夹并且应用程序当前没有打开要重命名的文件,则重命名成功共享访问被拒绝。

上面的批处理文件也可以用批处理文件中的单个命令行进行编码:

@for /F "eol=| tokens=1*" %%I in ('dir "* *" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /V /C:_TEMP- 2^>nul') do @ren "%%I %%J" "%%I_TEMP-%%J"

或者单个命令行实际上直接在命令提示符 window 中执行,如下所示,引用循环变量 IJ:

for /F "eol=| tokens=1*" %I in ('dir "* *" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /V /C:_TEMP- 2^>nul') do @ren "%I %J" "%I_TEMP-%J"

但是这个单一的命令行版本只适用于在文件名的第一部分和剩余部分之间始终只有一个 space 字符的文件,即它适用于 12345678 Hello World.txt 但不适用于 12345678 Hello World.txt.

要了解使用的命令及其工作原理,请打开命令提示符 window,在其中执行以下命令,然后阅读整个非常仔细地为每个命令显示所有帮助页面。

  • dir /?
  • echo /?
  • findstr /?
  • for /?
  • pause /?
  • ren /?
  • set /?

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

这里有一个可能的批处理文件解决方案,用于用给定的字符串替换第 9 个字符,_TEMP-它利用 PowerShell:

@Echo Off
Set "SD=%UserProfile%\Documents"
PowerShell -C "GI '%SD%\???????? *.txt'|Ren -N {$_.BaseName.Remove(8,1).Insert(8,'_TEMP-')+$_.Extension} -Wh"
Pause

只需将 2 行的 %UserProfile%\Documents 更改为包含 .txt 文件的文件夹,(如果它们也不是真正的 .txt 文件, 将 3 行的 txt 更改为适当的字符串或通配符。如果您要添加的字符串也不同,请将 3 行的 _TEMP- 替换为您想要的字符串太)。该脚本目前旨在向您展示如果要重命名文件会发生什么;如果您对输出满意,请将脚本更改为:

@Echo Off
Set "SD=%UserProfile%\Documents"
PowerShell -C "GI '%SD%\???????? *.txt'|Ren -N {$_.BaseName.Remove(8,1).Insert(8,'_TEMP-')+$_.Extension}"

如果您不想删除 8 个字符后的 space,则:

@Echo Off
Set "SD=%UserProfile%\Documents"
PowerShell -C "GI '%SD%\???????? *.txt'|Ren -N {$_.BaseName.Insert(8,'_TEMP-')+$_.Extension} -Wh"
Pause

…同样,如果您对输出感到满意,请将脚本更改为:

@Echo Off
Set "SD=%UserProfile%\Documents"
PowerShell -C "GI '%SD%\???????? *.txt'|Ren -N {$_.BaseName.Insert(8,'_TEMP-')+$_.Extension}"

我相信会有更好的方法来做到这一点,即使使用 PowerShell,但鉴于您提供的信息不足,我目前无法提出任何其他建议。