如何使用递增整数重命名多个图像?

问题描述 投票:0回答:1

假设我有几个图像,我需要重命名它们,并在每次迭代时添加一个递增的数字。

在这种情况下,无论名称如何,我都有三张图像,我想这样重命名它们。

1239.jpg => file1.jpg
file.jpg => file2.jpg
image.jpg => file3.jpg

我在命令提示符窗口中为此任务执行的命令是:

setlocal EnableDelayedExpansion
set filename=file
set counter=1
for /f "usebackq delims=*" %i in ('dir /b *.jpg') do (set /a counter+=1 ren "%i" "%filename%!counter!.jpg")

但是这会导致错误消息Missing operator

有人可以帮我吗?

for-loop cmd command-line command rename
1个回答
0
投票

如果使用Windows命令处理器完成文件重命名任务,则不容易实现

  1. 文件的文件扩展名不应更改,并且
  2. 应支持任何名称的文件,包括具有一个或多个&()[]{}^=;!'+,`~的文件,并且
  3. 目录中可能已经有带有新文件名之一的文件。

为了测试下面我首先在以下文件的目录中创建的批处理文件:

file.jpg
file1.jpg
file2.jpg
file3.jpg
file 4.jpg
File8.jpg
hello!.jpg
image.jpg

该目录位于FAT32驱动器上。文件系统FAT16,FAT32和exFAT返回一个未按名称排序为NTFS的匹配目录条目的列表,这意味着在以下代码的主FOR循环中由命令DIR输出的列表未排序且因此顺序无法预测。

当然可以附加DIR选项/ON以获取根据名称由DIR排序的文件名列表,但是实际上,在这种情况下,这并不是真正的帮助,特别是因为DIR进行严格的字母排序,而不是字母数字排序。

[严格字母排序返回十个文件名的列表,分别为file1.jpgfile10.jpgfile2.jpgfile3.jpg,...,file9.jpg,而字母数字排序返回十个文件名的列表,为[ C0],file1.jpgfile2.jpg,...,file3.jpgfile9.jpg

因此这是此文件重命名任务的批处理批处理文件:

file10.jpg

此批处理文件在执行时输出:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileName=file"

rem The user can run this batch file with a folder path in which all *.jpg
rem files should be renamed with an incremented number. Otherwise the
rem directory of the batch file is search for *.jpg files to rename.
if not "%~1" == "" (
    pushd "%~1" || exit /B
) else (
    pushd "%~dp0" || exit /B
)

set "FileCount=0"
set "DelayedLoopCount=0"
set "DelayedRenameCount=0"

rem Remove all existing environment variables in local environment of which
rem name starts with DelayedRename_ whereby the underscore is very important
rem because there is also the environment variable DelayedRenameCount.
for /F "delims==" %%I in ('set DelayedRename_ 2^>nul') do set "%%I="

rem Get a captured list of all *.jpg files in current directory and then
rem rename one file after the other if that is possible on no other file
rem has by chance already the new file name for the current file.
for /F "eol=| delims=" %%I in ('dir *.jpg /A-D /B 2^>nul') do call :RenameFile "%%I"
goto DelayedRenameLoop

:RenameFile
set /A FileCount+=1
set "NewName=%FileName%%FileCount%%~x1"

rem Has the file case-sensitive already the right name?
if %1 == "%NewName%" goto :EOF

rem Is the new file name the same as the current name
rem with exception of the case of one or more letters?
if /I %1 == "%NewName%" (
    echo Rename %1 to "%NewName%"
    ren %1 "%NewName%"
    goto :EOF
)

rem Is there no other file which has already the new name?
if not exist "%NewName%" (
    echo Rename %1 to "%NewName%"
    ren %1 "%NewName%"
    goto :EOF
)

rem Another file or folder has already the new name. Remember the name
rem of this file and the new file name with an environment variable for
rem a delayed rename after all other files have been renamed as far as
rem possible.
set /A DelayedRenameCount+=1
set "DelayedRename_%DelayedRenameCount%=|%~1|%NewName%"
goto :EOF

rem It could happen that "file15.jpg" should be renamed to "file3.jpg"
rem while "file3.jpg" exists already which should be renamed to "file12.jpg"
rem while "file12.jpg" exists already which should be renamed to "file20.jpg".
rem This extra loop is used for such worst case scenarios which is executed
rem in a loop until all files have been renamed with a maximum of 50 loop
rem runs in case of one file cannot be renamed and therefore blocking
rem renaming of another file. An endless running loop should be avoided.
rem A file cannot be renamed if a folder has by chance the new file name.
rem A file cannot be renamed if an application has opened the file with
rem a sharing access mode preventing the rename of the file as long as
rem being opened by this application.

:DelayedRenameLoop
if %DelayedRenameCount% == 0 goto EndBatch
for /F "tokens=1-3 delims=|" %%I in ('set DelayedRename_ 2^>nul') do if not exist "%%K" (
    echo Rename "%%J" to "%%K"
    ren "%%J" "%%K"
    set "%%I"
    set /A DelayedRenameCount-=1
)
set /A DelayedLoopCount+=1
if not %DelayedLoopCount% == 50 goto DelayedRenameLoop

:EndBatch
popd
endlocal

目录中的文件最后是:

Rename "file3.jpg" to "file4.jpg"
Rename "file 4.jpg" to "file5.jpg"
Rename "File8.jpg" to "file6.jpg"
Rename "hello!.jpg" to "file7.jpg"
Rename "image.jpg" to "file8.jpg"
Rename "file2.jpg" to "file3.jpg"
Rename "file1.jpg" to "file2.jpg"
Rename "file.jpg" to "file1.jpg"

最后一个文件呢?

尽管执行的是file1.jpg file2.jpg file3.jpg file4.jpg file5.jpg file6.jpg file7.jpg File8.jpg ,但文件名是File8.jpg而不是file8.jpg。好吧,FAT32对于仅在一个或多个字母的情况下更改表条目上的文件分配表的更新存在一些问题。

解决方案使用此批处理文件,并使用两个额外的FOR循环,并以ren "image.jpg" "file8.jpg"作为循环变量,并通过除去注释进行了优化。

#

此增强的批处理文件的结果甚至在FAT32上:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileName=file"

if not "%~1" == "" (pushd "%~1" || exit /B) else (pushd "%~dp0" || exit /B)

set "FileCount=0"
set "DelayedLoopCount=0"
set "DelayedRenameCount=0"
for /F "delims==" %%I in ('set DelayedRename_ 2^>nul') do set "%%I="
for /F "eol=| delims=" %%I in ('dir *.jpg /A-D /B 2^>nul') do call :RenameFile "%%I"
goto DelayedRenameLoop

:RenameFile
set /A FileCount+=1
set "NewName=%FileName%%FileCount%%~x1"
if %1 == "%NewName%" goto :EOF
if /I %1 == "%NewName%" (
    echo Rename %1 to "%NewName%"
    ren %1 "%NewName%"
    goto :EOF
)
if not exist "%NewName%" (
    echo Rename %1 to "%NewName%"
    ren %1 "%NewName%"
    for %%# in ("%NewName%") do if not "%%~nx#" == "%NewName%" ren "%%~nx#" "%NewName%"
    goto :EOF
)
set /A DelayedRenameCount+=1
set "DelayedRename_%DelayedRenameCount%=|%~1|%NewName%"
goto :EOF

:DelayedRenameLoop
if %DelayedRenameCount% == 0 goto EndBatch
for /F "tokens=1-3 delims=|" %%I in ('set DelayedRename_ 2^>nul') do if not exist "%%K" (
    echo Rename "%%J" to "%%K"
    ren "%%J" "%%K"
    for %%# in ("%%K") do if not "%%~nx#" == "%%K" ren "%%~nx#" "%%K"
    set "%%I"
    set /A DelayedRenameCount-=1
)
set /A DelayedLoopCount+=1
if not %DelayedLoopCount% == 50 goto DelayedRenameLoop

:EndBatch
popd
endlocal

执行file1.jpg file2.jpg file3.jpg file4.jpg file5.jpg file6.jpg file7.jpg file8.jpg 作为字符串分隔符的原因

|

例如,执行结果

set "DelayedRename_%DelayedRenameCount%=|%~1|%NewName%"

是文件夹名称中不允许使用竖线。因此,将环境变量的名称与当前文件名和新文件名后附加等号分开是一个很好的角色。这使得以后可以使用set "DelayedRename_1=|file.jpg|file1.jpg" set "DelayedRename_2=|file1.jpg|file2.jpg" set "DelayedRename_3=|file2.jpg|file3.jpg" 重命名文件并删除环境变量。

另请参见Microsoft文档:

文件名中允许使用等号。 * .jpg文件甚至可能具有文件名Using command redirection operators,这是使用=My Favorite Picute=.jpg执行的另一个原因,例如

|

随后会在FOR循环中将set "DelayedRename_4=|=My Favorite Picute=.jpg|file9.jpg" 分配给循环变量DelayedRename_4=,将I分配给循环变量=My Favorite Picute=.jpg,将J分配给循环变量file9.jpg,从而重命名延迟的文件。

注:每个FOR循环,括号中的结果为K

  • 在后台启动时,再使用'...'和[]进行另一个命令处理>
  • 捕获为处理STDOUT]而编写的输出,就像%ComSpec% /c '...'内部命令DIR
  • SET的输出一样>
  • 在执行批处理文件的cmd.exe期间等待,直到开始执行cmd.exe本身在命令行执行后终止(关闭)本身
  • 然后通过[[FOR依次处理捕获的行,忽略空行和在进行字符串定界后以定义的行尾字符开头的行,这就是在主cmd.exe的原因[FOR
  • 循环作为文件名可以以默认的行尾字符eol=|开头,在这里当然不应该忽略它。重定向操作符;必须在那些FOR命令行上使用脱字符号>进行转义,以便在执行命令

    FOR之前,Windows命令解释器处理此命令行时将其解释为文字字符。在后台启动的单独命令过程中嵌入的^dir命令行。

批处理文件不使用set,因为这会在具有一个或多个感叹号的文件名上引起麻烦,这些感叹号将被解释为在诸如delayed expansion的命令行上延迟的扩展环境变量引用的开始/结尾。因此,子例程用于主文件重命名循环,在该子例程上必须访问两个递增的计数器值。为了了解所使用的命令及其工作方式,请打开ren "%%J" "%%K"窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

command prompt

© www.soinside.com 2019 - 2024. All rights reserved.