PowerShell中/批处理脚本重命名每个文件,包括原名称+文件夹名(PowerShell/Bat

2019-09-30 20:31发布

我有以下文件夹结构:

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”。 我不想与文件夹的名称完全替换文件名,我只是希望它在最后一个下划线如果可能的话分开添加上。

一旦我做到了,我想删除所有包含在名为“未经批准”的文件,并删除任何“认可”文件,其中有一个“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"
)

Answer 1:

第一个解决方案仅适用于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
    • 30-04-2018
      • approved123_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>nul通过一种用于在一个单独的命令处理中执行开始在背景与cmd /CDIR输出要求与引用路径只是不含路径的文件名%%I在需要在其它命令行充分限定的文件名(文件路径+文件名+文件扩展名)。 输出的文件名由DIR处理背景命令处理的STDOUT通过用于捕获,然后通过线加工线。 因此,执行上面的命令DEL期间对文件分配表的变化不再重要。

还阅读有关微软的文章使用命令重定向操作符的的解释2>nul 。 重定向操作符>必须与插入符号字符被转义^FOR命令行被解释为文字字符时Windows命令解释程序进程执行命令,此命令执行该嵌入dir在一个单独的命令过程的命令行中背景启动。

但是,让我们假设目录结构是根据答复如下移动文件上一级文件夹 :

  • 四月报告
    • 2018年1月4日
      • dayreports
        • approved123.pdf
        • approved123_V2.pdf
        • unapproved123.pdf
    • 2018年1月4日
      • dayreports
        • approved123.pdf
        • unapproved123.pdf
    • 30-04-2018
      • dayreports
        • 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 /?


Answer 2:

这里一个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附加放慢参数只显示什么将被执行-如果输出看起来OK删除_WhatIf小号

运行脚本(用假文件夹五月)样品后,树:

> 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


文章来源: PowerShell/Batch script to rename each file to include original name + folder name