如何使用 Powershell 将文件名的前 7 个字符移动到末尾

How to move first 7 characters of a file name to the end using Powershell

我的公司有数百万份 pdf 格式的旧报告。它们通常以以下格式命名:2018-09-18 - ReportName.pdf

我们需要提交这些文件的组织现在要求我们以这种格式命名文件:Report Name - 2018-09.pdf

我需要将文件名的前7个字符移到末尾。我在想可能有一个简单的代码来执行这个任务,但我想不通。谁能帮帮我

谢谢!

Get-ChildItem 用一些 RegEx 和 Rename-Item 可以做到:

Get-ChildItem -Path "C:\temp" | foreach {

    $newName = $_.Name -replace '(^.{7}).*?-\s(.*?)\.(.*$)',' - .'
    $_ | Rename-Item -NewName $newName
}

正则表达式

'(^.{7}).*?-\s(.*?)\.(.*$)' / - .

  • (^.{7}) 匹配前 7 个字符
  • .*?-\s 匹配任何字符,直到(包括)第一个找到的 -(space 破折号 space)
  • (.*?)\. 匹配任何内容,直到找到第一个点 ( . )
  • (.*$) 匹配本例中的文件扩展名
  • - . 以更改后的顺序将它们放在一起

如果文件名中包含多个点 (.),这将无法正常工作。

这应该可行(添加了一些测试数据):

$test = '2018-09-18 - ReportName.pdf','2018-09-18 - Other name.pdf','other pattern.pdf','2018-09-18 - double.extension.pdf'

$test | % {
    $match = [Regex]::Match($_, '(?<Date>\d{4}-\d\d)-\d\d - (?<Name>.+)\.pdf')
    if ($match.Success) {
        "$($match.Groups['Name'].Value) - $($match.Groups['Date'].Value).pdf"
    } else {
        $_
    }
}

像这样 -

Get-ChildItem -path $path | Rename-Item -NewName {$_.BaseName.Split(' - ')[-1] + ' - ' + $_.BaseName.SubString(0,7) + $_.Extension} -WhatIf

解释-

  1. Split 将根据参数 - 分离文件名,[-1] 告诉 PowerShell select 最后一个分离值。
  2. SubString(0,7) 将从文件 BaseName 的第一个字符开始 select 7 个字符。
  3. 删除 -WhatIf 以应用重命名。

警告

  • 正如 jazzdelightsme 指出的那样,如果您要从日期;例如,2018-09-18 - ReportName.pdf2018-09-19 - ReportName.pdf 会产生 相同的 文件名,Report Name - 2018-09.pdf.

  • 无论哪种方式,我假设重命名操作是对原始文件的副本执行的。或者,您可以在枚举原件时使用 Copy-Item 在别处创建具有新名称的 副本 ,但 Rename-Item 的优点是它会报告 error 在名称冲突的情况下。

Get-ChildItem -Filter *.pdf | Rename-Item -NewName { 
  $_.Name -replace '^(\d{4}-\d{2})-\d{2} - (.*?)\.pdf$', ' - .pdf' 
} -WhatIf

-WhatIf 预览重命名操作;删除它以执行实际重命名。
-Recurse 添加到 Get-CildItem 调用以处理整个目录 subtree.
-Filter 的使用是可选的,但它可以加快处理速度。

  • 一个脚本块{ ... })被传递给Rename-Item-NewName参数,它启用动态使用字符串转换(替换)表达式重命名从 Get-ChildItem 接收的每个输入文件 ($_)。

  • -replace 运算符使用 regex(正则表达式)作为其第一个操作数,根据模式执行字符串替换;在这里,正则表达式分解如下:

    • ^(\d{4}-\d{2}) 在名称的开头 (^) 匹配类似 2018-09 的内容,并且 - 由于包含在 (...) 中 -捕获所谓的 捕获组 中的匹配项,可以通过其索引在替换字符串中引用该匹配项,即 </code>,因为它是 <em> 第一个</em> 捕获组。</p></li> <li><p><code>(.*?) 捕获文件名 的其余部分,不包括 捕获组 </code> 中的扩展名。 </p> <ul> <li><code>.*之后的?使得子表达式非贪婪,意思是它会给后续的子表达式一个匹配的机会,而不是尝试匹配尽可能多的字符(这是默认行为,称为 greedy)。

  • \.pdf$ 与末尾的文件扩展名 (.pdf) ($) 匹配 - 请注意大小写无关紧要。 . 被转义为 \.,因为它意在匹配 字面上的 此处(不转义,. 匹配 any单行字符串中的单个字符)。

  • - .pdf为替换字符串,将捕获组捕获的内容排列成想要的形式。

请注意,任何名称与正则表达式不匹配的文件都将被单独保留,因为如果不匹配,-replace 运算符会传递输入字符串,如果不匹配,Rename-Item 将不执行任何操作新名称与旧名称相同。