在Windows批处理文件中,我想通过简单地将年份字符串包装在括号中来重命名文件名中包含4位数字的年份(例如:“ 1999”)。示例:
home video 1998.avi
home vid 1987.mov
home_video (2002).avi
将成为
home video (1998).avi
home vid (1987).mov
home_video (2002).avi
请注意,如果已经将其括在括号中,则我不希望将它们加倍。
到目前为止,我只能用以下代码匹配包含年份字符串的文件名:
@echo off
REM Match file names with 4-digit year
setlocal enableDelayedExpansion
for /f "tokens=1* delims=" %%A in (
'dir /B "*"^|findstr "[1-2][0-9][0-9][0-9]" '
) do @echo %%A
pause
REM Now what?
所以我可以输出匹配文件名的列表,但是从那里我不知道如何定位findstr匹配的分组字符,以便将完整文件名解析为我认为需要的3个块:子字符串在匹配的组之前,组本身以及该组之后的子字符串。
在批处理文件中可以吗?
答案 0 :(得分:1)
我使用Total Commander(共享软件)已有20多年了,用于文件/文件夹重命名任务,这使它具有内置的多重重命名工具,只需单击几下即可轻松重命名文件和文件夹,结果可以在真正运行多重重命名之前进行查看,甚至可以在执行多重重命名后支持undo。好吧,实际上我使用Total Commander几乎完成了所有文件管理任务。
但是为这种非常特殊的文件重命名任务开发代码很有趣,但由于Windows命令处理器没有针对此类任务而设计,因此它具有所有限制。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R /C:"19[89][0123456789]" /C:"20[012][0123456789]"') do call :RenameFile "%%I"
endlocal
goto :EOF
:RenameFile
set "FileName=%~n1"
setlocal EnableDelayedExpansion
set "Year=1980"
:YearLoop
set "NewName=!FileName:%Year%=(%Year%)!"
if "!NewName!" == "!FileName!" (
if %Year% == 2029 goto ExitSub
set /A Year+=1
goto YearLoop
)
if "!FileName:(%Year%)=!" == "!FileName!" ren "%~1" "!NewName!%~x1"
:ExitSub
endlocal
goto :EOF
FOR 在以cmd.exe /C
在后台启动的单独命令过程中执行以下命令行:
dir /A-D-H /B 2>nul | C:\Windows\System32\findstr.exe /R /C:"19[89][0123456789]" /C:"20[012][0123456789]"
DIR 通过使用的选项输出当前目录中所有非隐藏文件的名称,仅包含文件名+扩展名,而没有文件路径。通过使用2>nul
将文件从句柄 STDERR 重定向到设备 NUL ,可以抑制当前目录不包含任何非隐藏文件的错误消息输出。 / p>
DIR 输出的文件名使用|
重定向,以处理命令 FINDSTR 的 STDIN ,该命令搜索区分大小写两个正则表达式解释的搜索字符串,其范围为1980
至1999
或2000
至2029
范围内的四个数字。不会检查四位数的匹配是否是较大数字(例如12000或19975)的一部分。也不会检查四位数的周围是否已经有圆括号。
FINDSTR 还将¹
,²
,³
解释为使用[0-9]
的数字,这就是使用[0123456789]
的原因真正只匹配那些10位数字字符中的任何一个。请阅读有关 FINDSTR 文章SS64 - FINDSTR和What are the undocumented features and limitations of the Windows FINDSTR command?
FINDSTR 输出所有在1980
至2029
范围内包含四位数的文件名,以处理后台命令过程的 STDOUT 。
请阅读有关Using Command Redirection Operators的Microsoft文章,以获取2>nul
和|
的解释。重定向操作符>
和|
必须用 FOR 命令行上的脱字符号^
进行转义,以在Windows命令解释器处理此命令行时将其解释为原义字符。在执行命令 FOR 之前,该命令将在后台启动的单独命令进程中执行嵌入的dir
命令行。
FOR 捕获这些行并逐行处理它们。选项eol=
(行尾)的默认值是分号,因此 FOR 将忽略所有以分号开头的文件名。因此,指定eol=|
是因为文件名中不能使用竖线,因此所有捕获的文件名均由 FOR 处理。
FOR 默认情况下会在空格/制表符上拆分每个文件名,并且仅将第一个子字符串(令牌)分配给指定的循环变量I
。通过使用delims=
(它定义了一个空的定界符列表)来禁用此拆分行为。 tokens=*
与此不同,这会导致从文件名中删除前导空格。文件名可以以一个或多个空格开头,尽管这种情况很不常见。
文件名还可以包含感叹号!
,在使用延迟的环境变量扩展时也必须考虑这些感叹号。每个文件名都传递给子例程以进行进一步处理。
使用循环将圆括号中的年份替换为分配给循环变量Year
的year的所有实例,直到新文件名与当前文件名不同,因为对搜索字符串而言,替换确实为正。 for /L %%J in (1980,1,2029) do ...
未被使用,因为一旦找到正确的文件名年份就无法退出此循环。
在文件名中找到年份后,将检查今年是否尚未嵌入括号中,以避免将名称为home vid (1987).mov
的文件重命名为home vid ((1987)).mov
。因此,例如home video 1998.avi
最终重命名为home video (1998).avi
。
包含两个具有四个或更多数字的数字的文件名也无法正确处理,因为此代码无法找出该文件名中的年份。
此批处理代码的速度并不是很快,但是它应该可以在列出的限制下使用。
要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。
call /?
dir /?
echo /?
endlocal /?
findstr /?
goto /?
if /?
ren /?
set /?
setlocal /?
另请参阅Where does GOTO :EOF return to?
PS:名称中带有(
或)
的文件名使处理批处理文件变得更加困难,因为在这种情况下,文件名必须始终用双引号括起来,例如文件名在Windows代码处理器(
中,由于)
和cmd.exe
而包含空格字符也具有特殊含义,如上面的代码所示。另请参见How does the Windows Command Interpreter (CMD.EXE) parse scripts?