重命名文件的文件移动任务,文件名中的日期重新格式化,可以使用以下批处理文件完成:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BaseFolder=C:\ABC"
set "!Jan=01"
set "!Feb=02"
set "!Mar=03"
set "!Apr=04"
set "!May=05"
set "!Jun=06"
set "!Jul=07"
set "!Aug=08"
set "!Sep=09"
set "!Oct=10"
set "!Nov=11"
set "!Dec=12"
for /F "eol=| delims=" %%G in ('dir "%BaseFolder%\* - * * * * * * - * * * *, *.txt" /A-D-H /B 2^>nul') do for /F "eol=| tokens=1,7,12-14 delims=, " %%H in ("%%G") do for /F "tokens=2 delims==" %%# in ('set !%%J 2^>nul') do md "%BaseFolder%\DEF" 2>nul & move /Y "%BaseFolder%\%%G" "%BaseFolder%\DEF\%%H_%%I_%%#%%K%%L" >nul
endlocal
前两个命令行完全定义了所需的执行环境。
接下来定义基本文件夹的路径,文本文件移动到分配给环境变量BaseFolder的基本文件夹的子文件夹中。
接下来的命令行定义环境变量,名称缩写为月份,名称前面为!,其对应的两位数字为值。
第一个 FOR 循环在后台再开始一个 cmd.exe 并带有选项 /c 和在 ' 中指定的命令行作为附加参数附加在带有通配符模式的基本文件夹中搜索要移动的文本文件。处理在后台启动的cmd.exe 进程的DIR 的输出(标准输出)由处理批处理文件的cmd.exe 捕获。捕获的行是通配符模式匹配的所有非隐藏*.txt 文件的文件名。
第一个FOR循环在启动cmd.exe 后一行接一行地自行终止。默认情况下,首先使用普通空格和水平制表符作为字符串分隔符将每行拆分为子字符串。如果第一个子字符串以分号开头,则忽略该行以进行进一步处理。否则,第一个子字符串将分配给指定的循环变量,FOR 将执行接下来指定的命令。这里不需要这种行为,因为文件名肯定包含空格,甚至可能文件名以分号开头。出于这个原因,选项eol=| 用于将竖线定义为任何文件名都不能包含的行尾字符,选项delims= 用于指定字符串分隔符的空列表以禁用行拆分行为。因此,DIR 输出的不带路径的整个文件名被分配给循环变量G。
第二个FOR 处理带有文件扩展名的文件名字符串。这次需要使用逗号和普通空格作为字符串分隔符的拆分行为,因为以下子字符串很有趣:
- 用
tokens=1 引用的第一个子字符串abcdef 分配给指定的循环变量H。
-
tokens= 选项字符串中用7 引用的第七个子字符串xxxx 根据ASCII table 分配给下一个循环变量I。
- 第十二个子字符串
Sep 在分配给下一个循环变量 J 的 tokens= 选项字符串中用 12 引用。
- 分配给循环变量
K的tokens=选项字符串中12和14之间的-引用的第十三个子字符串21。
- 分配给循环变量
L的tokens=选项字符串中14引用的第十四个子字符串2021.txt。
文件名可能包含一个或多个!,因此最好避免使用需要使用延迟扩展的引用环境变量。每个工作日处理的文件也不多。
因此,文件名中缩写月份的两位数字是通过使用另外一个FOR命令在后台运行cmd.exe和选项/c和命令来获得的SET 使用缩写月份作为环境变量名称,前面带有!。命令 SET 输出以处理后台命令的 STDOUT 处理以感叹号和缩写月份开头的所有环境变量。感叹号只是为了避免意外输出另一个名称也以当前月份缩写的三个字符开头的环境变量。环境变量名称通常不以感叹号开头,至少不是任何预定义的 Windows 环境变量。
SET 输出变量名、等号和赋值。此输出由第三个 FOR 捕获并处理,这次使用等号作为分隔符,并分配给指定的循环变量#,仅等号后面的两位数。
因此,现在所有子字符串都分配给了新文件名中所需的循环变量。
因此,如果目标目录尚不存在,则执行命令 MD 创建目标目录,并通过从句柄 STDERR 重定向错误消息来抑制已存在的错误消息(标准错误)到设备 NUL。
Next 独立于命令 MD 命令的结果执行,命令 MOVE 移动基本文件夹中的文件,文件名和扩展名分配给第一个循环变量 G FOR 到目标文件夹,新文件名与第二个和第三个 FOR 确定的子字符串连接。通过将一个文件重定向到设备 NUL 来抑制成功移动一个文件的消息输出,同时将错误消息输出到控制台窗口。
最后一个命令ENDLOCAL恢复初始环境。
如果驱动器 C: 使用 NTFS 作为文件系统并且文本文件的文件名和基本文件夹路径中不包含感叹号,也可以使用以下批处理文件。
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "BaseFolder=C:\ABC"
set "Jan=01"
set "Feb=02"
set "Mar=03"
set "Apr=04"
set "May=05"
set "Jun=06"
set "Jul=07"
set "Aug=08"
set "Sep=09"
set "Oct=10"
set "Nov=11"
set "Dec=12"
md "%BaseFolder%\DEF" 2>nul
for %%G in ("%BaseFolder%\* - * * * * * * - * * * *, *.txt") do for /F "eol=| tokens=1,7,12-14 delims=, " %%H in ("%%~nxG") do move /Y "%%G" "%BaseFolder%\DEF\%%H_%%I_!%%J!%%K%%L" >nul
endlocal
此批处理文件执行得更快,因为没有其他cmd.exe 实例在后台启动,并且目标文件夹仅创建一次(希望成功)。它使用delayed expansion 来获取文件名中缩写月份的两位数,因此只需要两个 FOR 循环:
- 第一个 FOR 循环用于在此 FOR 循环的每次迭代中访问文件系统,以直接从文件中获取与通配符模式匹配的下一个文件名和完整路径系统。这适用于在 NTFS 驱动器上移动文件,但在 FAT32 或 exFAT 驱动器上可能无法正常工作,因为在 FAT 驱动器上,文件系统条目会随着文件的每次成功移动而改变。出于这个原因,通常最好先加载到
cmd.exe 的内存中处理批处理文件,其名称与第一个批处理文件所做的通配符模式匹配的所有文件的列表,然后在内存中处理此列表文件系统条目在每次循环迭代中永久更改。
- 第二个 FOR 循环用于从新文件名中所需的文件名中获取子字符串,这与在第一个批处理文件中所做的完全一样。
要了解所使用的命令及其工作原理,请打开command prompt 窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。
dir /?
echo /?
endlocal /?
for /?
md /?
move /?
set /?
setlocal /?
阅读有关Using command redirection operators 的Microsoft 文档,了解2>nul 的解释。重定向运算符 > 必须在 FOR 命令行上使用插入字符 ^ 进行转义,以便在 Windows 命令解释器在执行命令 FOR 之前处理此命令行时解释为文字字符> 在后台启动的单独命令进程中执行嵌入的dir 或set 命令行。
有关运算符& 的说明,另请参阅single line with multiple commands using Windows batch file。