是的,这可能会发生,尤其是在 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:\Windows\System32\cmd.exe /C dir *.txt /A-D /B 2>nul
于是又在后台启动了一个命令进程,它执行 DIR
- 在当前目录中搜索
- 仅用于文件,因为选项
/A-D(属性不是目录)
- 包括设置了隐藏属性的文件(使用
/A-D-H 排除隐藏文件)
- 匹配通配符模式
*.txt
- 并且由于选项
/B 仅以裸格式输出文件名。
通过将其重定向到设备 NUL强>.
阅读有关Using Command Redirection Operators 的Microsoft 文章,了解2>nul 的解释。重定向运算符 > 必须在 FOR 命令行上使用插入符号 ^ 转义,以便在 Windows 命令解释器在执行命令 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%\System32\findstr.exe /B /I /L /V /C:"Seekret file "') do ren "%%I" "Seekret file %%I"
FINDSTR在这里用于从DIR输出的文件名列表中输出并重定向到FINDSTR的STDIN > 所有文件名
- 做不因为
/V(反转结果)
-
开始 因为选项
/B
-
不区分大小写,因为选项
/I
- 由于选项
/L 被解释为 literally(与 /C: 冗余)
- 字符串
Seekret file 。
选项/C: 需要指定包含两个空格的搜索字符串,因为仅使用"Seekret file" 将导致在行首搜索Seekret 或file 时不区分大小写。在仅使用"..." 指定的搜索字符串中,FINDSTR 将每个空格解释为类似于 Perl 正则表达式字符串中的| 的 OR 表达式。
使用/C: 指定的搜索字符串被隐式解释为文字字符串,但使用/R(而不是/L)可以将此字符串解释为正则表达式字符串,在该字符串上解释空格作为空间而不是作为 OR 表达式。可以使用多次/C:指定多个搜索字符串。
我对使用 FINDSTR 的建议:始终使用 /L 或 /R 以明确 FINDSTR 以及命令行的每个读者如何FINDSTR 应该解释用"..." 或/C:"..." 指定的搜索字符串。