繁体   English   中英

PowerShell/Batch 脚本重命名每个文件以包含原始名称 + 文件夹名称

[英]PowerShell/Batch script to rename each file to include original name + folder name

我有以下文件夹结构:

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

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

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

完成此操作后,我想删除名称中包含“未批准”的所有文件,并删除同一文件夹中包含“approved_V2”的所有“已批准”文件(版本 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"
)

第一个解决方案仅适用于 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 驱动器上,结果是:

  • 四月报告
    • 01-04-2018
      • 批准123_V2_01-04-2018.pdf
    • 02-04-2018
      • 批准123_02-04-2018.pdf
    • 30-04-2018
      • 批准123_30-04-2018.pdf

但是此批处理文件在 FAT32 或 exFAT 驱动器上无法按预期工作,因为文件April reports\01-04-2018\approved123_V2.pdf被处理了三次,导致最终名称为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" /ADH /B 2>nulFOR使用在后台使用cmd /C启动的单独命令进程执行。 DIR仅输出不带路径的文件名,这需要使用%%I引用路径,其中在其他命令行上需要完全限定的文件名(文件路径 + 文件名 + 文件扩展名)。 DIR输出的处理后台命令进程的STDOUT的文件名被FOR捕获,然后逐行处理。 因此,在运行命令DELREN期间文件分配表的变化不再重要。

另请阅读有关使用命令重定向运算符的 Microsoft 文章,了解2>nul的说明。 重定向运算符>必须在FOR命令行上使用脱字符^进行转义,以便在 Windows 命令解释器在执行命令FOR之前处理此命令行时解释为文字字符,该命令使用在后台启动的单独命令进程执行嵌入式dir命令行。

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

  • 四月报告
    • 01-04-2018
      • 日报表
        • 批准123.pdf
        • 批准123_V2.pdf
        • 未批准123.pdf
    • 01-04-2018
      • 日报表
        • 批准123.pdf
        • 未批准123.pdf
    • 30-04-2018
      • 日报表
        • 批准123.pdf
        • 未批准123.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 /?

这是一个深入任何子目录的 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM