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

时间:2018-09-19 13:05:57

标签: regex powershell file-rename batch-rename rename-item-cmdlet

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

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

我需要将文件名的前7个字符移到末尾。我认为可能有一个简单的代码可以执行此任务,但我无法弄清楚。谁能帮我。

谢谢!

4 个答案:

答案 0 :(得分:1)

注意事项

  • 正如jazzdelightsme所指出的,假设您要从日期中删除日期部分,则所需的重命名操作可能会导致名称冲突。例如2018-09-18 - ReportName.pdf2018-09-19 - ReportName.pdf将导致相同文件名Report Name - 2018-09.pdf

  • 无论哪种方式,我都假设重命名操作是对原始文件的副本执行的。另外,您可以在枚举原始文档时使用Copy-Item用其他名称创建副本,但是Rename-Item的优点是它将报告错误 如果发生名称冲突。

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

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

  • 脚本块{ ... })传递到Rename-Item的{​​{1}}参数,该参数可以动态重命名每个输入文件({使用字符串转换(替换)表达式从-NewName接收到的{1}}。

  • $_运算符使用 regex (正则表达式)作为其第一个操作数,以基于模式执行字符串替换。此处,正则表达式分解如下:

    • Get-ChildItem在名称的开头(-replace)匹配^(\d{4}-\d{2})之类的东西,并且-由于被包含在2018-09中,因此在所谓的捕获组,由于它是 first 捕获组,因此可以在替换字符串中通过其索引^进行引用。

    • (...)捕获其余文件名 ,但不包括捕获组$1中的扩展名。

      • (.*?)之后的$2使子表达式成为 non-greedy ,这意味着它将为后续的子表达式也提供匹配的机会,而不是尝试匹配尽可能多的字符(这是默认行为,称为 greedy )。
    • ?与文件名扩展名(.*)的末尾(\.pdf$)相匹配-请注意大小写无关紧要。 .pdf被转义为$,因为此处是字面意义上的匹配(不进行转义,.匹配任何单个字符(在单行字符串中)。

    • \.是替换字符串,它以所需的形式排列捕获组所捕获的内容。

请注意,任何名称与正则表达式都不匹配的文件都会被静静地放置,因为.运算符将在没有匹配项的情况下传递输入字符串,而$2 - $1.pdf将不执行任何操作。名称与旧名称相同。

答案 1 :(得分:0)

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

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

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

正则表达式

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

  • (^.{7})匹配前7个字符
  • .*?-\s匹配任何字符,直到(包括)第一个找到的-(空格破折号)
  • (.*?)\.匹配所有内容,直到找到第一个点(。)
  • (.*$)在这种情况下匹配文件扩展名
  • $2 - $1.$3以更改后的顺序将它们放在一起

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

答案 2 :(得分:0)

这应该起作用(添加了一些测试数据):

$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 {
        $_
    }
}

答案 3 :(得分:0)

类似的东西-

JAVA_HOME

说明-

  1. C:\Progra~1\Java\jdk1.7.0_71将根据参数Get-ChildItem -path $path | Rename-Item -NewName {$_.BaseName.Split(' - ')[-1] + ' - ' + $_.BaseName.SubString(0,7) + $_.Extension} -WhatIf 分隔文件名,Split告诉PowerShell选择最后一个分隔值。
  2. -从文件[-1]的第一个字符开始选择7个字符。
  3. 删除SubString(0,7)以应用重命名。