在批处理文件中使用循环重命名x表示y

时间:2018-01-05 20:06:43

标签: windows loops batch-file rename

我在重命名文件时遇到字符串文字问题:

我有许多包含子字符串x的文件,我想用它们代替y,这可能出现在文件名的任何部分。

cheese.txt
Sarah_cheese_Parker.txt
cheese_Brookes.txt

应该成为:

Louise.txt
Sarah_Louise_Parker.txt
Louise_Brookes.txt

set x="cheese"
set y="Louise"

这是我到目前为止所拥有的

for %%f in (x*.txt) do 
(
    echo %%f
    call :processit "%%f"
)
goto finished

:processit
ren x%i%.txt y%i%.txt

goto :finished

:finished
dir *.txt /b

我并不担心文件名中包含%的并发症。

2 个答案:

答案 0 :(得分:1)

批处理文件应存储在包含所有* .txt文件的目录中,并通过双击执行。

@echo off
for /F "eol=| delims=" %%I in ('dir "*cheese*.txt" /A-D /B 2^>nul') do call :RenameFile "%%I"
set "NewName="
pause
goto :EOF

:RenameFile
set "NewName=%~nx1"
set "NewName=%NewName:cheese=Louise%"
ren "%~1" "%NewName%"
goto :EOF

命令 DIR 搜索

  • 仅针对文件,因为/A-D(非属性目录)
  • 仅在当前目录中,因为未使用其他/S
  • 表示包含cheese
  • 的* .txt文件
  • 以裸格式输出,因为/B找到的文件的名称带有文件扩展名,但没有路径。

DIR 命令行由 FOR 在后台单独的命令进程中执行,后者捕获此命令进程的输出(= command DIR )写入处理 STDOUT

DIR 输出的可能错误,如果未在目录中找到与通配符模式匹配的任何文件以处理 STDERR ,则会通过将2>nul重定向到设备来抑制的 NUL 即可。另请阅读有关Using Command Redirection Operators的Microsoft文章,了解2>nul的说明。重定向运算符>必须使用 FOR 命令行上的插入符^进行转义,以便在执行命令之前Windows命令解释程序处理此命令行时将其解释为文字字符FOR ,它在后台启动的单独命令进程中执行嵌入式dir命令行。

命令 FOR 处理从 DIR 输出中捕获的每一行。选项;禁用 FOR 忽略以eol=|开头的行的默认行为。字符|不能用于文件/文件夹名称,因此不能在文件/文件夹名称的开头。 FOR 将水平制表符和空格中的每一行拆分为子字符串的默认行为由选项delims=禁用,指定一个空的分隔符列表。所以 FOR 确实为每个文件名分配了文件扩展名,但是没有循环变量I的路径。

此处在捕获的文件名列表上运行 FOR 非常重要,而不是让 FOR 本身以递归方式搜索TXT文件,否则会在文件中发生重命名由于在循环迭代期间目录条目更改而跳过某些TXT文件。

对于每个文件名,调用子例程RenameFile,并将完整文件名作为用双引号括起来的第一个参数传递给子例程。双引号是必要的,以便在文件名或文件路径中处理包含空格或其中一个字符&()[]{}^=;!'+,`~的文件名。

使用子程序而不是直接在 FOR 循环中执行剩余代码,因为这将需要使用延迟环境变量扩展,如果处理文件的文件/文件夹名称包含,则会导致问题一个或多个惊叹号。

在子例程RenameFile中,没有路径的当前文件的名称被分配给环境变量NewName

接下来,对文件名应用字符串替换,以cheese替换不区分大小写的所有 Louise

然后执行文件重命名,同时指定要重命名的文件和带有文件扩展名的新名称,不带路径 REN 所需的路径。

可以将 ECHO 命令左侧插入ren以首先运行批处理文件,以便检查文件重命名是否按预期完成。

可以在/S之后添加 DIR 选项/B以进一步搜索当前目录的所有子目录中的{。{1}}的* .txt文件的递归文件名。在这种情况下, DIR 将输出具有完整路径的所有文件名。但是编写的批处理文件仍然可以正常工作。

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

  • cheese
  • call /?
  • dir /?
  • echo /?
  • for /?
  • goto /?
  • pause /?
  • ren /?

另见Where does GOTO :EOF return to?

答案 1 :(得分:1)

此代码可以满足您的需求。请注意,*%x%*.txt是“包含子字符串x的文件的右侧通配符,可能出现在文件名的任何部分”。

@echo off
setlocal EnableDelayedExpansion

set "x=cheese"
set "y=Louise"

for %%f in (*%x%*.txt) do (
    echo %%f
    call :processit "%%f"
)
goto finished

:processit
set "name=%~1"
ren "%~1" "!name:%x%=%y%!"
exit /B

:finished
dir *.txt /b

此解决方案中的关键点是,一个子字符串替换另一个子字符串只能在变量中完成,因此必须将%1子例程参数分配给{ {1}}变量。

第二点是,为了将一个子串替换为另一个子串,当两个串都存储在变量中时,需要使用标准name 首先展开%expansion%x子字符串,然后延迟y 以在!expansion!变量中执行替换;这是通过以下方式实现的:

name

最后一点是在这种情况下你真的不需要子程序,因此最终的代码可能更简单:

ren "%~1" "!name:%x%=%y%!"