使用批处理脚本重命名多个文件

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

我有很多这种格式的文件:

D:\images\AAA_BBB\image\whatever1.jpg  
D:\images\AAA_BBB\image\whatever2.jpg
D:\images\FFF_EEE_CCC\image\asdf1.jpg
D:\images\FFF_EEE_CCC\image\asdf2.jpg
D:\images\WWW_XXX_YYY_ZZZ\image\someimage1.jpg
D:\images\WWW_XXX_YYY_ZZZ\image\someimage2.jpg

我想使用绝对文件路径的子字符串移动和重命名这些文件,并删除原始文件,以便结果如下所示,以

0
开头。

D:\images\AAA\AAA_0.jpg
D:\images\AAA\AAA_1.jpg
D:\images\EEE\EEE_0.jpg
D:\images\EEE\EEE_1.jpg
D:\images\YYY\YYY_0.jpg  
D:\images\YYY\YYY_1.jpg

请注意,带下划线的文件夹中的令牌数量可以是任意长度

以下尝试只会给我从前面开始的第二个令牌。使用“Tokens=-2”获取倒数第二个令牌不会输出任何内容。

@echo off & setlocal EnableDelayedExpansion 

PushD "D:\images" || Exit /B

For /F "EOL=? Delims=" %%G In ('Dir /A:D /B 2^>NUL
 ^| %SystemRoot%\System32\findstr.exe /I /R  "^[^_][^_]*_[^_][^_]*_[^_][^_]*_"'
) Do For /F "Tokens=2 EOL=? Delims=_" %%H In ("%%G") Do (
    Set "i=-1"
    For /F "EOL=? Delims=" %%I In ('Dir "%%G\image" /A:-D /B') Do (
        Set /A i += 1
        SetLocal EnableDelayedExpansion
        Ren "%%G\image\%%I" "%%H_!i!%%~xI" && (
            If Not Exist "%%H\." MD "%%H"
            Move /Y "%%G\image\%%H_!i!%%~xI" "%%H"
        )
        EndLocal
    )
)

PopD

然后我使用不同的逻辑,尝试两个

for
循环来获取最后一个令牌,然后是第二个最后一个令牌,但它不起作用。

@echo off & setlocal EnableDelayedExpansion 

PushD "D:\images" || Exit /B

For /F "EOL=? Delims=" %%G In ('Dir /A:D /B 2^>NUL
 ^| %SystemRoot%\System32\findstr.exe /I /R  "^[^_][^_]*_[^_][^_]*_[^_][^_]*_"'
) Do (
    Set "dirName=%%G"
    Set "lastSegment="
    For %%H In ("!dirName:_=" "!") Do (
        Set "secondLastSegment=!lastSegment!"
        Set "lastSegment=%%~H"
    )
    Set "segment=%%~xG"
    Set "i=-1"
    For /F "EOL=? Delims=" %%I In ('Dir "%%G\image" /A:-D /B') Do (
        Set /A i += 1
        SetLocal EnableDelayedExpansion
        Ren "%%G\image\%%I" "!secondLastSegment!_!i!!segment!" && (
            If Not Exist "!secondLastSegment!\." MD "!secondLastSegment!"
            Move /Y "%%G\image\!secondLastSegment!_!i!!segment!" "!secondLastSegment!"
        )
        EndLocal
    )
)

PopD
windows batch-file rename move
4个回答
1
投票

这应该有效:

@echo off
setlocal EnableDelayedExpansion

pushd "D:\images" || exit /B

for /D %%d in (*_*) do (
   set "oldName=%%d"
   for %%b in (".!oldName:_=.!") do for %%c in ("%%~Nb") do set "newName=%%~Xc"
   set "newName=!newName:~1!"
   md "!newName!"
   set "i=-1"
   for %%f in ("%%d\image\*.jpg") do (
      set /A i+=1
      move "%%~f" "!newName!\!newName!_!i!%%~Xf"
   )
)

您的示例有很多不需要或多余的代码...

  • 一般来说,当你只想处理文件或文件夹时,没有必要使用
    for /F
    命令; plain
    for
    for /D
    for /F
    更简单且工作速度更快。
  • for /D %%d in (*_*) do
    命令处理所有至少带有一个下划线的文件夹;我不明白你为什么使用
    findstr
    和复杂的正则表达式......
  • 请参阅我的技巧,使用 ~Name
    ~eXtension
    FOR 命令参数修饰符提取
    第二个姓氏
  • 如果您处理每个源文件夹一次,则只需创建相应的目标文件夹一次。您无需检查每个文件中是否存在这样的文件夹。如果目标文件夹以前可能存在,您只需对每个源文件夹检查一次...

0
投票

根据您提供的信息,这对您有帮助吗?

@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion

Set "BaseDir=D:\images"

PushD "%BaseDir%" 2>NUL || Exit /B
For /F "EOL=? Delims=" %%G In ('Dir "*_*" /A:D-L /B /O:N 2^>NUL
 ^| %SystemRoot%\System32\findstr.exe /IR "[^_][^_]*_[^_][^_]*"') Do (
    PushD "%%G"
    For /F "Tokens=1,* Delims=:" %%H In ('Dir "image\*.jpg" /A:-D-L /B 2^>NUL
     ^| %SystemRoot%\System32\findstr.exe /INR "\.jpg$"') Do (
        For /F "Delims=_" %%J In ("%%G") Do (
            If Not Exist "%BaseDir%\%%J\." MD "%BaseDir%\%%J"
            Move /Y "%BaseDir%\%%G\image\%%~I" "%BaseDir%\%%J\%%J_%%H%%~xI"
        ) 1>NUL
    )
    PopD
)
PopD

请注意,您可能还有空目录,您也可能希望清理它们!


0
投票
@ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION

SET "sourcedir=u:\images"

FOR /f %%e IN ('DIR /b /ad "%sourcedir%\*_*"') DO (
 rem %%e has firstlevel subdirectory name - must have at least one "_"
 SET "L2=%%e"
 FOR %%o IN (!L2:_^= !) DO SET "destsub=!prevpart!"&SET "prevpart=%%o"
 FOR /f %%y IN ('dir /b /a-d "%sourcedir%\%%e\image\*.jpg"') DO (
  MD "%sourcedir%\!destsub!" >nul 2>NUL
  SET "needtomove=Y"
  FOR /L %%u IN (0,1 9999) DO IF DEFINED needtomove IF NOT EXIST "%sourcedir%\!destsub!\!destsub!_%%u.jpg" move "%sourcedir%\%%e\image\%%y" "%sourcedir%\!destsub!\!destsub!_%%u.jpg" >nul&SET "Needtomove="
 )
)

GOTO :EOF

在应用于真实数据之前,始终验证测试目录。

查找包含

_
的每个子目录。通过将
_
替换为空格并使用
_
来查找倒数第二个
for
分隔的元素。对于 ssubdirectory\image 中的每个
*.jpg
,尝试使其目标(2>nul 抑制诸如“目录已存在”之类的错误消息),然后尝试在目标目录中查找第一个可用名称(因为不能保证杂散文件目的地中尚不存在)并进行移动。


0
投票

您的代码中有几个问题,我想消除它们:

  • 您的
    findstr
    过滤器太严格,因此它只会处理示例列表中的最后两个图像。我建议完全删除它并使用目录掩码
    *_*
    来代替。
  • 不需要尝试为每个图像文件创建目标目录;每个源目录尝试一次就足够了。
  • 通过
    if exist
    检查目录是否存在,将
    \.
    附加到路径时会导致错误的结果(当它指向文件而不是目录时,也会报告为存在);相反,应附加
    \*
    ,因此文件将被报告为不存在。
  • 您应该为要处理的图像文件指定一个文件名掩码,例如
    *.jpg
    和/或
    *.png
    ,以过滤掉不需要的图像文件。
  • 也许您应该为要处理的图像文件指定排序顺序,因为否则,文件系统会确定顺序,这可能不是您所期望的。
  • 变量
    segment
    将为空,因为
    %%~xG
    将为空(根据您的示例)。您很可能是指
    %%~xI
  • 虽然从技术上讲是可行的,但没有必要先重命名当前图像文件,然后将其移动到另一个子目录中;一次移动操作就足够了。
  • 移动图像文件后,可能会残留空子目录,应将其清理干净。
  • 当使用
    setlocal
    进行环境本地化时,大多数情况下不需要使用
    pushd
    ,因为
    setlocal
    也包含当前工作目录。请记住,与
    popd
    相比,缺少
    pushd
    可能会留下不需要的
    setlocal
    堆栈条目,因为当批处理脚本终止时,
    endlocal
    始终会隐式执行。
  • 延迟变量扩展不应全局启用,因为名称中包含
    !
    ^
    的文件/目录名称可能会导致问题。

这是您的代码,已修复上述问题(不触及内在方法):

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Usage of `pushd`/`popd` is usually not needed when using `setlocal`/`endlocal`:
cd /D "%~dp0images" || exit /B

for /F "eol=| delims=" %%G in ('
    rem/ // The `findstr` filter was too strong and is unnecessary ^(a simple `dir` is enough^)^^! ^& ^
        2^> nul dir /B /A:D-H-S-L "*_*"
') do (
    set "dirName=%%G"
    set "lastSegment="
    rem // Toggle delayed expansion to have it enabled only when necessary to not lose `!`-symbols:
    setlocal EnableDelayedExpansion
    for %%H in ("!dirName:_=" "!") do for %%J in ("!lastSegment!") do (
        endlocal
        set "secondLastSegment=%%~J"
        set "lastSegment=%%~H"
        setlocal EnableDelayedExpansion
    )
    rem /* Creation of the target directory is now done once per source directory
    rem    (to check whether a directory exists, append `\*` rather than `\.`): */
    if not exist "!secondLastSegment!\*" md "!secondLastSegment!"
    endlocal
    set "targetDir=%%G\image"
    rem // Since `%%~xG` is going to be blank, `segment` will be empty and is therefore useless:
    rem/ set "segment=%%~xG"
    set /A "i=-1"
    rem /* The `dir` should specify the file name mask(s) to exclude non-image files
    rem    (a sort order is now specified; hidden, system and linked items are now excluded): */
    for /F "eol=| delims=" %%I in ('cd /D "%%G\image" ^&^& dir /B /A:-D-H-S-L /O:DN "*.jpg" "*.png"') do (
        set /A "i+=1"
        set "fileName=%%I"
        rem // Variable `segment` is empty; use `%%~xI` instead:
        set "fileExt=%%~xI"
        setlocal EnableDelayedExpansion
        set "newFileName=!secondLastSegment!_!i!!fileExt!"
        rem/ ren "!targetDir!\!fileName!" "!newFileName!" && (
            rem The target directory has already been created at this point.
            rem/ move /Y "!targetDir!\!newFileName!" "!secondLastSegment!"
        rem/ )
        
        
        rem /* Instead of renaming and then moving, a single move operation suffices
        rem    (note that variable `segment` is empty, hence use `%%~xI` instead): */
        > nul move /Y "!targetDir!\!fileName!" "!secondLastSegment!\!newFileName!"
        rem // Clean up potentially empty sub-directory:
        2> nul rd "!targetDir!"
        endlocal
    )
    rem // Clean up potentially empty source directory:
    2> nul rd "%%G"
)

endlocal
exit /B
© www.soinside.com 2019 - 2024. All rights reserved.