我可以使用以下命令为一系列文本文件添加前缀:
:: rename files
for %%a in (*.txt) do (
ren "%%a" "Seekret file %%a"
:: ECHO %%a Seekret file %%a
)
哪个会转
a.txt
b.txt
c.txt
到
Seekret file a.txt
Seekret file b.txt
Seekret file c.txt
但是,上面的代码似乎使用前缀重命名了第一个文件两次。我最终得到
Seekret file Seekret file a.txt
我不知道为什么。有什么想法吗?
使用
for /f "delims=" %%a in ('dir /b /a-d *.txt') do (
正在发生的事情是您正在使用的版本将重命名的文件视为新文件。dir
版本构建文件名列表,然后在每行上执行for
,因此列表已经构建且是静态的,cmd
不会尝试对移动目标进行操作。
另外 - 使用rem
,而不是在代码块(括号中的指令序列)中::
,因为这种形式的注释实际上是一个损坏的标签,并且标签不允许在code block
中
是的,这可能会发生,尤其是在 FAT32 和 exFAT 驱动器上,因为这些文件系统不会返回与通配符模式匹配的目录条目列表,以按字母顺序调用可执行文件。for
处理一个接一个匹配*.txt
目录条目,命令ren
导致更改目录条目,即在迭代文件名列表时对其进行修改。
解决方案是使用:
for /F "eol=| delims=" %%I in ('dir *.txt /A-D /B 2^>nul') do ren "%%I" "Seekret file %%I"
在这种情况下,FOR在后台%ComSpec% /c
运行,在'
之间指定的命令行,这意味着将 Windows 安装到目录 C:\Windows 中:
C:WindowsSystem32cmd.exe /C dir *.txt /A-D /B 2>nul
因此,在后台启动了另一个命令进程,该进程执行DIR
- 在当前目录中搜索
- 仅用于文件,因为选项
/A-D
(属性不是目录) - 包括设置了隐藏属性的文件(使用
/A-D-H
排除隐藏文件) - 匹配通配符模式
*.txt
- 并以裸格式输出,由于选项
/B
.
DIR输出的用于处理STDERR的错误消息(如果未找到任何符合这些条件的目录条目)将通过将其重定向到设备NUL来抑制。
阅读有关使用命令重定向运算符的Microsoft文章,了解2>nul
的说明。当 Windows 命令解释器在执行命令 FOR 之前处理此命令行时,重定向运算符>
必须在FOR命令行上使用插入符号^
进行转义,以使用在后台启动的单独命令进程执行嵌入的dir
命令行。
没有路径的文件名由DIR输出,以处理后台命令进程的STDOUT。此输出分别由执行批处理文件的命令进程FOR捕获。
启动的命令进程自身终止后,FOR处理捕获的文件名列表。因此,在循环迭代期间对目录所做的所有更改都不再重要。文件名列表不再更改。
需要选项eol=| delims=
来获取一个接一个的完整文件名,以循环变量I
,即使以;
开头或包含空格字符也是如此。eol=|
将默认的行尾字符;
重新定义为任何文件名都不能包含的垂直条。delims=
定义一个空的分隔符列表,以禁用普通空格和水平制表符上的默认换行行为。
注意:::
是无效标签,不是注释。不允许在命令块中使用标签,这通常会导致命令块执行时出现未定义的行为。使用命令REM(备注)进行注释。
更好的是:
for /F "eol=| delims=" %%I in ('dir *.txt /A-D /B 2^>nul ^| %SystemRoot%System32findstr.exe /B /I /L /V /C:"Seekret file "') do ren "%%I" "Seekret file %%I"
FINDSTR在这里用于从DIR输出的文件名列表中输出,并重定向到FINDSTR的STDIN所有文件名
- 不要因为
/V
(倒置结果) - 开始是因为选项
/B
- 由于选项
/I
不区分大小写 - 由于选项
/L
的字面解释(冗余到/C:
) - 字符串
Seekret file
.
需要选项/C:
来指定包含两个空格的搜索字符串,因为仅使用"Seekret file"
会导致在行首对Seekret
ORfile
进行字面搜索和不区分大小写。在仅用"..."
指定的搜索字符串中,每个空格都被FINDSTR解释为 OR 表达式,就像 Perl 正则表达式字符串中的|
一样。
使用/C:
指定的搜索字符串被隐式解释为文字字符串,但通过使用/R
(而不是/L
),可以将此字符串解释为正则表达式字符串,其中空格被解释为空格而不是 OR 表达式。可以使用多次/C:
指定多个搜索字符串。
我对使用FINDSTR的建议:始终使用/L
或/R
来明确FINDSTR和命令行的每个读者应该如何解释用"..."
或/C:"..."
指定的搜索字符串。
我想我也会扔进去,因为我真的不喜欢循环遍历dir
输出,而且目前没有其他人在考虑这个脚本已经运行:
@echo off
set "dir=C:YourRootDirectory"
set "pfx=Seekret file "
setlocal enabledelayedexpansion
for /r "%dir%" %%A in (*.txt) do (
set "txt=%%~nA"
if not "!txt:~0,13!"=="%pfx%" ren "%%A" "%pfx%%%~nxA"
)
pause
for /r
将递归循环遍历所有.txt文件,将每个文件设置为参数%%A
(每次迭代),将变量txt
设置为参数%%A
减少到仅其名称(%%~nA
),然后将文本文件的前 13 个字符与示例前缀进行比较(包含空格时长度为 13 个字符):Seekret file
) - 如果它们匹配,则循环不执行任何操作;如果它们不匹配,循环将重命名%%A
以在开头包含前缀。如果不希望它是递归的,可以改用for %%A in ("%dir%"*.txt) do (
。除此之外,您只需根据前缀是什么或要检查的文件名中有多少个字母来更改!txt:~0,13!
。您也不必设置目录和前缀变量,我更喜欢这样做,因为它使块看起来更干净 - 并且更容易返回并更改一个值,而不是该值出现在脚本中的每个位置。
参考:对于/r、ren、变量子字符串