我可以在FOR命令中使用FOR / L计数器变量吗?

时间:2019-05-04 18:09:30

标签: batch-file for-loop variables

::for /l %%n in (0, 1, 6) do (

for /F "skip=1 delims=" %%i in (path.txt) do set "dirvar=%%i"&goto nextline
:nextline

for /F "skip=1 delims=" %%i in (file.txt) do set "filevar=%%i"&goto nextline
:nextline

for /F "skip=1 delims=" %%i in (dotonefile.txt) do set "dotvar=%%i"&goto nextline
:nextline

SET dirvar=%dirvar%
SET filevar=%filevar%
SET dotvar=%dotvar%
SET dirfile=%dirvar%%filevar%
SET dirdotfile=%dirvar%%dotvar%

IF EXIST %dirfile% (
    del %dirdotfile%
) ELSE (
    rename %dirdotfile% %dirfile%
)

::)

我上面的批处理脚本可以运行一次,因此效果很好。它从三个单独的文本文件中将第二行读入变量。然后,它会测试以查看文件名是否在目录中,以及是否命名为IMG001.jpg并删除IMG001.1.jpg。在同一目录中。如果在目录中未找到IMG001.jpg,则它将目录中的IMG001.1.jpg重命名为IMG001.jpg。

path.txt只是一个文本文件,其中包含文件夹路径列表,例如:

F:\My Pictures\2005-Misc\
F:\My Pictures\2006-Misc\
F:\My Pictures\2007-Misc\

file.txt只是一个带有列表文件名的文本文件,其中第1行是目录中的文件,也是path.txt文件的第1行。因此,在2005-Misc文件夹中可能有IMG001.jpg,在2006-Misc文件夹中可能有IMG001.jpg,在2007-Misc文件夹中可能有IMG001.jpg:

IMG001.JPG
IMG001.JPG
IMG001.JPG

类似于dotonefile.txt,它是path.txt中列出的相应目录中的文件名列表。因此,在文件夹2005-Misc中有一个IMG001.1.jpg,在文件夹2006-Misc中有一个,在文件夹2007-Misc中有一个。

IMG001.1.JPG
IMG001.1.JPG
IMG001.1.JPG

我想循环播放此脚本并重复它,以便它从文本文件到变量读取第1到n行(n可以进行硬编码,目前在7以上),然后测试并重命名每个文件名。

我尝试取消注释第一行和最后一行,然后在三个for循环中,我将硬编码的“ 1”替换为“ %% n”,但批处理文件不会因“命令的语法错误而运行错误” ”。以下是我的无效尝试。关于如何调整运行的任何建议?我尝试了各种组合,使一个新的计数变量最终增加1,并使用各种形式的变量的延迟扩展,但没有任何效果。

for /l %%n in (0, 1, 6) do (

for /F "skip=%%n delims=" %%i in (path.txt) do set "dirvar=%%i"&goto nextline
:nextline

for /F "skip=%%n delims=" %%i in (file.txt) do set "filevar=%%i"&goto nextline
:nextline

for /F "skip=%%n delims=" %%i in (dotonefile.txt) do set "dotvar=%%i"&goto nextline
:nextline

SET dirvar=%dirvar%
SET filevar=%filevar%
SET dotvar=%dotvar%
SET dirfile=%dirvar%%filevar%
SET dirdotfile=%dirvar%%dotvar%

IF EXIST %dirfile% (
    del %dirdotfile%
) ELSE (
    rename %dirdotfile% %dirfile%
)

)

1 个答案:

答案 0 :(得分:2)

主要问题是Windows命令处理器cmd.exe不支持命令块内的标签,这些标签在使用命令块执行命令之前已被完全解析。请阅读详细信息How does the Windows Command Interpreter (CMD.EXE) parse scripts?

解决方案正在使用子例程。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /L %%N in (0,1,6) do call :ProcessFiles %%N
endlocal
goto :EOF

:ProcessFiles
if not %1 == 0 ( set "SkipOption=skip=%1 " ) else ( set "SkipOption=" )
set "DirVar="
for /F "%SkipOption%eol=| delims=" %%I in (path.txt) do set "DirVar=%%I" & goto GetFileVar
:GetFileVar
set "FileVar="
for /F "%SkipOption%eol=| delims=" %%I in (file.txt) do set "FileVar=%%I" & goto GetDotVar
:GetDotVar
set "DotVar="
for /F "%SkipOption%eol=| delims=" %%I in (dotonefile.txt) do set "DotVar=%%I" & goto CheckFile

:CheckFile
set "DirFile=%DirVar%%FileVar%"
set "DirDotFile=%DirVar%%DotVar%"
if exist "%DirFile%" (
    del "%DirDotFile%"
) else (
    rename "%DirDotFile%" "%DirFile%"
)
goto :EOF

一种更聪明的方法是使用此批处理文件代码,而根本不使用文本文件。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I  in ('dir "F:\My Pictures\*.1.JPG" /A-D /B /S 2^>nul') do (
    for %%J in ("%%~dpnI") do (
        if exist "%%~dpnJ%%~xI" (
            del "%%I"
        ) else (
            ren "%%I" "%%~nJ%%~xI"
        )
    )
)
endlocal

FOR 循环从%ComSpec% /C在后​​台执行另一个cmd.exe命令过程开始,以执行命令行:

dir "F:\My Pictures\*.1.JPG" /A-D /B /S 2>nul

DIR 搜索具有指定选项的

  • 文件是由于选项/A-D(属性而非目录)
  • 不区分大小写的匹配模式*.1.JPG
  • 由于选项F:\My Pictures在目录/S及其所有子目录中
  • 并且仅由于选项/B就以裸格式输出
  • 由于选项/S而具有文件扩展名和完整路径的文件名。
如果在符合这些条件的整个目录树中找不到文件,则

DIR 将输出一条错误消息。通过将其重定向到设备 NUL ,可以抑制此错误消息。

阅读有关Using Command Redirection Operators的Microsoft文章,以获取2>nul的解释。当Windows命令解释器在执行命令之前处理此命令行时,重定向操作符>必须在 FOR 命令行上使用脱字符号^进行转义,才能被解释为文字字符。 FOR ,它将在后台启动的单独命令进程中执行嵌入式dir命令行。

FOR 捕获所有输出以处理已启动命令进程的 STDOUT ,并在启动cmd.exe完成后逐行处理捕获的文本。

FOR 忽略此处根本不会出现的空行。 FOR 还将忽略以;开头的行,因为它是行尾选项的默认选项。由于 DIR 输出具有完整路径的文件名,因此行不可能以;开头。但是eol=|仍然用于将竖线定义为行尾,文件夹/文件名无法包含。

FOR 默认情况下使用正常空格和水平制表符作为分隔符将每一行拆分为子字符串(令牌)。这里不希望出现这种情况,因为文件路径可能包含空格字符。因此,delims=用于定义一个空的定界符列表,以禁用行拆分行为。

内部的 FOR 用于将循环变量J分配给.1.JPG左边的字符串。

IF 条件检查当前文件*.JPG的文件*.1.JPG是否与当前文件位于同一目录中,在这种情况下文件*.1.JPG是如果根据只读属性,当前帐户的文件权限和当前文件共享访问权限完全允许此文件删除或文件重命名操作,则删除或以其他方式重命名为*.JPG

但是让我们假设图像文件名可以是与*.jpg匹配的任何文件名,并且不仅可以有*.1.jpg,还可以有*.2.jpg*.99.jpg个图像文件,也就是说,文件扩展名.jpg前的小数点后的任何数字。在这种情况下, DIR 不足以获取带有文件扩展名和完整路径的文件名列表。此外,还需要使用带有正则表达式的 FINDSTR 来过滤文件名列表。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I  in ('dir "F:\My Pictures\*.*.jpg" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R "\.[0123456789][0123456789]*\.jpg$"') do (
    for %%J in ("%%~dpnI") do (
        if exist "%%~dpnJ%%~xI" (
            del "%%I"
        ) else (
            ren "%%I" "%%~nJ%%~xI"
        )
    )
)
endlocal

第一个 FINDSTR 输出仅从 STDIN 中读取的行,

  • 由于选项/I而匹配区分大小写
  • 正则表达式\.[0123456789][0123456789]*\.jpg$
  • 由选项/R明确声明。

正则表达式匹配一个字符串,该字符串由点,一个或多个数字,另一个点和在行尾找到的字符串jpg组成。因此, DIR 输出的Hello.World.jpg之类的文件名与 FINDSTR 不匹配,因此, FINDSTR 也未输出,因此未被处理 FOR
但是,根据同一目录中Hello.World.393.jpg的存在,将处理诸如Hello.World.jpg之类的文件名,然后将其删除或重命名为Hello.World.jpg

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • call /?
  • del /?
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • ren /?rename /?
  • set /?
  • setlocal /?

另请参阅Where does GOTO :EOF return to?