PowerShell /批处理脚本重命名每个文件以包括原始名称+文件夹名称

时间:2018-07-15 12:17:33

标签: powershell batch-file directory rename

我具有以下文件夹结构:

April reports
├─01-04-2018
│ ├─approved123.pdf
│ ├─approved123_V2.pdf
│ └─unapproved123.pdf
│
├─02-04-2018
│ ├─approved123.pdf
│ └─unapproved123.pdf
╎
╎
└─30-04-2018
  ├─approved123.pdf
  └─unapproved123.pdf

四月的每一天的每个文件夹包含一个具有相同名称(“ approved123”或“ unapproved123”)的已批准和未批准报告。有些包含V2。

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

完成此操作后,我想删除名称中包含“ unapproved”的所有文件,并删除同一文件夹中存在“ approved_V2”的所有“ approved”文件(版本2取代了原始)。

第一步,我尝试编写批处理脚本(编写批处理或Powershell脚本的初学者),但是它不起作用,或者多次向每个文件添加文件夹名称:

@echo off
From the folder "April Reports"
rem Process each date
for /D %%d in (*) do (
    cd "%%d"
    rem rename all files
    for /d %%a in (*) do for %%b in ("%%~dpa\.") do ren "%%~a" "%%~nxb_%%~nxa"
)

2 个答案:

答案 0 :(得分:5)

第一个解决方案仅适用于NTFS驱动器,并且希望该批处理文件位于包含April reports作为子目录的目录中。

@echo off
for /D %%I in ("%~dp0April reports\??-??-????") do (
    for %%J in ("%%I\approved*.pdf") do (
        if exist "%%I\un%%~nxJ" del /F "%%I\un%%~nxJ"
        if exist "%%I\%%~nJ_V*.pdf" ( del "%%J" ) else ren "%%J" "%%~nJ_%%~nI.pdf"
    )
)

在NTFS驱动器上,结果是:

  • 四月报告
    • 2018年1月4日
      • approved123_V2_01-04-2018.pdf
    • 2018年2月4日
      • approved123_02-04-2018.pdf
    • 2018年4月30日
      • approved123_30-04-2018.pdf

但是此批处理文件无法在FAT32或exFAT驱动器上正常工作,因为文件April reports\01-04-2018\approved123_V2.pdf被处理了3次,最终由于文件分配表中的文件条目列表而导致了名称approved123_V2_01-04-2018_01-04-2018_01-04-2018.pdf的出现匹配模式approved*.pdf会在运行内部循环时发生变化。

针对FAT32和exFAT驱动器的解决方案是将捕获的文件名列表用于内部循环。

@echo off
for /D %%I in ("%~dp0April reports\??-??-????") do (
    for /F "delims=" %%J in ('dir "%%I\approved*.pdf" /A-D-H /B 2^>nul') do (
        if exist "%%I\un%%~nxJ" del /F "%%I\un%%~nxJ"
        if exist "%%I\%%~nJ_V*.pdf" ( del /F "%%I\%%J" ) else ren "%%I\%%J" "%%~nJ_%%~nI.pdf"
    )
)

现在,结果与FAT32和exFAT驱动器上的第一个批处理文件相同。

命令行dir "%%I\approved*.pdf" /A-D-H /B 2>nul FOR 在以cmd /C在后​​台启动的单独命令过程中执行。 DIR 仅输出不带路径的文件名,该文件名需要使用%%I引用路径,而在其他命令行上则需要完整的限定文件名(文件路径+文件名+文件扩展名)。 DIR 输出的用于处理后台命令过程的 STDOUT 的文件名由 FOR 捕获,然后逐行处理。因此,在运行命令 DEL REN 时文件分配表上的更改不再重要。

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

但是根据问题Move files up one folder level,我们假定目录结构如下:

  • 四月报告
    • 2018年1月4日
      • 日报表
        • approved123.pdf
        • approved123_V2.pdf
        • unapproved123.pdf
    • 2018年1月4日
      • 日报表
        • approved123.pdf
        • unapproved123.pdf
    • 2018年4月30日
      • 日报表
        • approved123.pdf
        • unapproved123.pdf

通过对第二批处理文件进行少量修改,可以实现与上面发布的结果相同的结果。

@echo off
for /D %%I in ("%~dp0April reports\??-??-????") do (
    for /F "delims=" %%J in ('dir "%%I\dayreports\approved*.pdf" /A-D-H /B 2^>nul') do (
        if exist "%%I\dayreports\un%%~nxJ" del /F "%%I\dayreports\un%%~nxJ"
        if exist "%%I\dayreports\%%~nJ_V*.pdf" ( del /F "%%I\dayreports\%%J" ) else move /Y "%%I\dayreports\%%J" "%%I\%%~nJ_%%~nI.pdf" >nul
    )
    rd "%%I\dayreports" 2>nul 
)

dayreports被另外添加到文件路径,并且使用命令 MOVE 代替命令 REN 将剩余文件在文件夹层次结构中使用新命令向上移动一级文件名。如果最终为空,则使用命令 RD 删除文件夹dayreports

这里是另一个变体,它仅处理目录的整个目录树中的所有approved*.pdf,其中包含独立于文件系统工作的批处理文件,并且对于两个目录结构都具有目录名称中带有日期的日期的PDF文件或子目录dayreports中。通过检查要移动/重命名的文件是否已经包含文件夹名称(日期),这样可以避免多次处理approved*.pdf

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "%~dp0approved*.pdf" /A-D-H /B /S 2^>nul') do (
    if exist "%%~dpI\un%%~nxI" del /F "%%~dpI\un%%~nxI"
    if exist "%%~dpI\%%~nI_V*%%~xI" ( del /F "%%I" ) else call :MoveFile "%%I"
)
endlocal
rem Avoid a fall through to the subroutine.
goto :EOF

rem The subroutine MoveFile 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.

:MoveFile
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

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

  • call /? ...还解释了%~dp0,它扩展为驱动器和参数0的路径,该参数是批处理文件的完整路径,始终以反斜杠结尾。
  • del /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • if /?
  • move /?
  • rd /?
  • ren /?
  • set /?
  • setlocal /?

答案 1 :(得分:1)

这里有一个PowerShell解决方案,可以深入到任何子目录中。

  • 它使用正则表达式来标识所有相关的名称部分
  • 如果检测到un前缀或具有相同名称和后缀_V2的文件,
    它设置了一个删除标志($Del
  • 然后删除当前文件或通过用父目录名称替换数字(123)的部分重命名。

Get-ChildItem *.pdf -Recurse | 
  Where-Object BaseName -match '(un)?(approved)(\d+)(_v2)?' |
    ForEach-Object {$Del = $False
      If ($matches[1] -eq 'un')       {$Del = $True}
      If (Test-Path (Join-Path $_.Directory.Fullname ($_.BaseName+"_V2.pdf"))){$Del = $True }
      If ($Del) {
        Remove-Item $_.FullName -whatif
      } else {
        Rename-Item $_.FullName -NewName ("{0}_{1}{2}{3}" -f `
           $matches[2],$_.Directory.Name,$Matches[4],$_.Extension) -WhatIf
      }
    }

Remove-ItemRename-Item cmdlet附加了-WhatIf参数,以仅显示将执行的内容-如果输出看起来正常,则删除_WhatIf s

运行脚本后的示例树(带有假May文件夹):

> tree /f
Auflistung der Ordnerpfade für Volume RamDisk
Volumeseriennummer : 5566-7788
A:.
├───April reports
│   ├───01-04-2018
│   │       approved_01-04-2018_V2.pdf
│   │
│   ├───02-04-2018
│   │       approved_02-04-2018.pdf
│   │
│   └───30-04-2018
│           approved_30-04-2018.pdf
│
└───May reports
    ├───01-05-2018
    │       approved_01-05-2018_V2.pdf
    │
    ├───02-05-2018
    │       approved_02-05-2018.pdf
    │
    └───30-05-2018
            approved_30-05-2018.pdf