【问题标题】:Batch script to rename files in sub folders according to folder name根据文件夹名称重命名子文件夹中文件的批处理脚本
【发布时间】:2018-12-23 19:02:03
【问题描述】:

接上一个问题:PowerShell/Batch script to rename each file to include original name + folder name

我有几个月的以下文件夹结构:

2017
 │
 ├─April reports
 │   ├─01-04-2018
 │   │ ├─XYZAPPROVED123.pdf
 │   │ ├─XYZAPPROVED123_V2.pdf
 │   │ └─XYZUNAPPROVED123.pdf
 │   │
 │   ├─02-04-2018
 │   │ ├─XYZAPPROVED123.pdf
 │   │ └─XYZUNAPPROVED123.pdf
 │   │
 │   │
 │   └─30-04-2018
 │     ├─XYZAPPROVED123.pdf
 │     └─XYZUNAPPROVED123.pdf
 │ 
 ├─ May reports
 │   ├─01-04-2018
 │   │ ├─XYZAPPROVED123.pdf
 │   │ ├─XYZAPPROVED123_V2.pdf
 │   │ └─XYZUNAPPROVED123.pdf
 │   │
 │   ├─02-04-2018
 │   │ ├─XYZAPPROVED123.pdf
 │   │ └─XYZUNAPPROVED123.pdf
 │   │
 │   │
 │   ├─30-04-2018
 │      ├─XYZAPPROVED123.pdf
 .
 .
 .
 ├─December reports (etc)

当月每一天的每个文件夹都包含一个已批准和未批准的同名报告(“XYZAPPROVED123”或“XYZUNAPPROVED123”)。有些包含 V2。

我想重命名每一个,以便删除“123”并将文件夹名称(日期)包含在文件名中,例如“XYZAPPROVED_01-04-2018”。我不想用文件夹的名称完全替换文件名,我只想将它添加到末尾,如果可能的话,用下划线分隔。

完成此操作后,我想删除名称中包含“XYZUNAPPROVED”的所有文件,并删除同一文件夹中包含“XYZAPPROVED_V2”的所有“XYZAPPROVED”文件(版本 2 取代原创)。

我已经设法使用下面的脚本获得一个批处理脚本来处理一个月(4 月)的报告。我遇到的问题是添加一个额外的循环,以便我可以运行它所有的几个月。

四月脚本(可行):

@echo off
cd "<actual path>"
for /D %%I in ("<actual path>\????-??-??") do (
    for %%J in ("%%I\XYZ*.pdf") do (
        if exist "%%I\XYZUN*" del /F "%%I\XYZUN*.pdf"
        if exist "%%I\%%~nJ_V*.pdf" ( del "%%J" ) else ren "%%J" 
"%%~nJ_%%~nI.pdf"
    )
)

所有月份的脚本-(我运行它时没有任何反应)

@echo off
cd "<actual path>"
 for /D %%H in ("<actual path>") do (
 rem Enter into the month name folder
  rem process each date
  for /D %%I in ("%%H\????-??-??") do (

      for %%J in ("%%I\XYZ*.pdf") do (
      if exist "%%I\XYZUN*" del /F "%%I\XYZUN*.pdf"
      if exist "%%I\%%~nJ_V*.pdf" ( del "%%J" ) else ren "%%J" "%%~nJ_%%~nI.pdf"

  )

 )
)

我错过了什么?

【问题讨论】:

    标签: batch-file directory rename


    【解决方案1】:

    这是 this answer 中的最后一个批处理文件,为新要求在批处理文件顶部定义的每个文件名的开头使用固定前缀而重写。

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    set "Prefix=XYZ"
    for /F "delims=" %%I in ('dir "%~dp0%Prefix%Approved*.pdf" /A-D-H /B /S 2^>nul') do call :ProcessFile "%%I"
    endlocal
    rem Avoid a fall through to the subroutine.
    goto :EOF
    
    rem The subroutine ProcessFile first assigns full qualified file name
    rem of found approved PDF file to environment variable FullFileName.
    rem All occurrences of defined prefix after a backslash are substituted
    rem by backslash, defined prefix and additionally the two characters UN.
    rem A PDF file with that name in same directory as the found approved PDF
    rem is deleted if existing which means there is still an unapproved PDF
    rem file for an already approved PDF file.
    
    rem Next the subroutine checks if there is one more approved PDF file
    rem starting with same name, but there is additionally _V and any other
    rem string in which case the approved PDF file without _V* in name is
    rem deleted and subroutine is exited.
    
    rem Otherwise the subroutine assigns path of passed file name ending with
    rem a backslash to environment variable FilePath. Next the backslash is
    rem removed from file path. Then is checked if the file path ends with
    rem folder name "dayreports" in which case also this folder is removed
    rem from file path. The file path is processed by command FOR to get
    rem the string after last backslash referenced with %%~nxJ which is the
    rem name of the folder of which name should be in new file name. Before
    rem moving the file with new name containing the date, it is checked if
    rem the current file name ends already with an underscore and the name
    rem of the folder which should be the date. The subroutine is exited
    rem if this condition is true to avoid double processing an already
    rem processed file in a previous execution of this batch file.
    
    :ProcessFile
    setlocal EnableDelayedExpansion
    set "FullFileName=%~1"
    set "UnapprovedFile=!FullFileName:\%Prefix%=\%Prefix%Un!"
    if exist "%UnapprovedFile%" del /F "%UnapprovedFile%"
    endlocal
    
    if exist "%~dp1\%~n1_V*%~x1" (
        del /F %1
        goto :EOF
    )
    
    set "FilePath=%~dp1"
    set "FilePath=%FilePath:~0,-1%"
    if /I "%FilePath:~-11%" == "\dayreports" set "FilePath=%FilePath:~0,-11%"
    for %%J in ("%FilePath%") do set "FolderName=%%~nxJ"
    set "FileName=%~n1"
    if "%FileName:~-11%" == "_%FolderName%" goto :EOF
    move /Y %1 "%FilePath%\%~n1_%FolderName%%~x1" >nul
    goto :EOF
    

    有一个非常简单的方法可以删除目录树的所有目录中的所有*unapproved*.pdf文件,这与同一目录中是否存在*approved*.pdf文件无关:

    del /A /F /Q /S "%~dp0*unapproved*.pdf"
    

    带有使用参数的命令DEL删除

    • 因为/Q而安静
    • 由于/S,批处理文件目录及其所有子目录中的所有*unapproved*.pdf
    • 包括*unapproved*.pdf,因为/F 设置了只读属性
    • 包括*unapproved*.pdf,因为/A 设置了隐藏属性。

    子程序ProcessFile 中的setlocal ... endlocal 块可以在FOR循环之前在批处理文件顶部使用此命令行首先删除,这会导致很多更快地执行批处理文件。

    我不知道是否建议删除所有*unapproved*.pdf而不检查同一目录中是否有对应的*approved*.pdf

    【讨论】:

      【解决方案2】:

      这是一个可以实现您想要的解决方案 - 查看所有解释性 cmets (rem):

      @echo off
      setlocal EnableExtensions DisableDelayedExpansion
      
      rem // Define constants here:
      set "_ROOT=%~dp0TEST"       & rem // (path of the root directory)
      set "_DIR1=????"            & rem // (mask for level-1 sub-directories (year))
      set "_DIR2=* reports"       & rem // (mask for level-2 sub-directories (month))
      set "_DIR3=??-??-????"      & rem // (mask for level-3 sub-directories (day))
      set "_NAMEREN=approved"     & rem // (partial name of files to keep)
      set "_NAMEDEL=unapproved"   & rem // (partial name of files to delete)
      set "_MASKREN=*%_NAMEREN%*" & rem // (name pattern for files to keep)
      set "_MASKDEL=*%_NAMEDEL%*" & rem // (name pattern for files to delete)
      set "_FILEEXT=.pdf"         & rem // (name extension for all files to process)
      set "_VERSUFF=V"            & rem // (beginning of version suffix in file names)
      set "_KEEPSUFF=#"           & rem // (set non-empty to keep version suffix)
      
      rem // Build search string for version suffix:
      set "SEARCH=_%_VERSUFF%[0123456789][0123456789]*"
      rem // Walk through all level-1 sub-directories:
      for /D %%C in ("%_ROOT%\%_DIR1%") do (
          rem // Walk through all level-2 sub-directories:
          for /D %%D in ("%%~C\%_DIR2%") do (
              rem // Walk through all level-3 sub-directories:
              for /D %%E in ("%%~D\%_DIR3%") do (
                  rem // Loop through all files to delete:
                  for %%F in ("%%~E\%_MASKDEL%%_FILEEXT%") do (
                      rem // Delete current file:
                      del "%%~F"
                  )
                  rem // Store path and name of current sub-directory:
                  set "LOC=%%~E" & set "SUB=%%~nxE"
                  rem // Loop through cached and sorted list of all files to potentially keep:
                  for /F "delims= eol=|" %%F in ('
                      2^> nul dir /B /A:-D /O:N "%%~E\%_MASKREN%%_FILEEXT%"
                  ') do (
                      rem // Store file name and extension:
                      set "VER=" & set "FILE=%%~nF" & set "EXT=%%~xF"
                      rem // Check if current file name has got a version suffix:
                      echo(%%~nF| > nul findstr /I /E "%SEARCH%" && (
                          rem // Version suffix encountered, hence extract it:
                          setlocal EnableDelayedExpansion
                          for %%H in ("!FILE:_=" "!") do (
                              endlocal
                              set "VER=_%%~H"
                              setlocal EnableDelayedExpansion
                          )
                          endlocal
                          rem /* Check whether there are other files with same name but with another
                          rem    version suffix appended: */
                          for %%I in ("%%~E\%_MASKREN%_%_VERSUFF%*%_FILEEXT%") do (
                              rem // Filter for correct version suffix:
                              echo(%%~nI| > nul findstr /I /E "%SEARCH%" && (
                                  rem // Extract version suffix:
                                  set "NUM=" & set "TEST=%%~nI"
                                  setlocal EnableDelayedExpansion
                                  for %%J in ("!TEST:_=" "!") do (
                                      endlocal
                                      set "NUM=_%%~J"
                                      setlocal EnableDelayedExpansion
                                  )
                                  rem /* Check whether the other version suffix is higher (or equal)
                                  rem    than the one of the current file:
                                  if !VER:*_%_VERSUFF%^=! lss !NUM:*_%_VERSUFF%^=! (
                                      rem // Other version suffix is higher, so delete current file:
                                      if exist "!LOC!\!FILE!!EXT!" del "!LOC!\!FILE!!EXT!"
                                  )
                                  endlocal
                              )
                          )
                      ) || (
                          rem /* No version suffix encountered, hence check if there is a file with
                          rem    the same name but with a version suffix appended: */
                          for %%G in ("%%~E\%%~nF_%_VERSUFF%*%%~xF") do (
                              rem // Filter for correct version suffix:
                              echo(%%~nG| > nul findstr /I /E "%SEARCH%" && (
                                  rem // Delete current file as there is a newer version:
                                  if exist "%%~E\%%~F" del "%%~E\%%~F"
                              )
                          )
                      )
                      rem // Check whether current file has been deleted:
                      if exist "%%~E\%%~F" (
                          rem // Keep version suffix only if desired:
                          if not defined _KEEPSUFF set "VER="
                          rem // Extract the partial file name to keep:
                          setlocal EnableDelayedExpansion
                          for /F "delims=| eol=|" %%K in ("_!FILE:%_NAMEREN%=|!") do (
                              endlocal
                              set "NAME=%%K%_NAMEREN%"
                              setlocal EnableDelayedExpansion
                          )
                          rem // Rename kept file as desired:
                          ren "!LOC!\!FILE!!EXT!" "!NAME:~1!_!SUB!!VER!!EXT!"
                          endlocal
                      )
                  )
              )
          )
      )
      
      endlocal
      exit /B
      

      此脚本从与每天相关的子目录中删除以下文件:

      • 名称中包含unapproved 的所有*.pdf 文件;
      • *.pdf 文件名称中带有approved 但没有版本后缀_V,以防另一个*.pdf 文件名称中带有approved 但附加了版本后缀;
      • 名称中带有approved 和版本后缀_V*.pdf 文件,其附加的版本号不是遇到的最大版本号;

      脚本在每天相关的子目录中保留并重命名以下文件:

      • *.pdf 文件,名称中带有approved 和版本后缀_V,其附加的版本号是遇到的最大版本号;保留approved 之前的部分,之后的部分替换为_ 加上父目录名称;版本后缀可以选择保留(见常量_KEEPSUFF);

      【讨论】:

        猜你喜欢
        • 2016-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-07
        • 2022-08-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多