如何使用 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
解释-
Split
将根据参数 -
分离文件名,[-1]
告诉 PowerShell select 最后一个分离值。
SubString(0,7)
将从文件 BaseName
的第一个字符开始 select 7 个字符。
- 删除
-WhatIf
以应用重命名。
警告:
正如 jazzdelightsme 指出的那样,如果您要从日期;例如,2018-09-18 - ReportName.pdf
和 2018-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
将不执行任何操作新名称与旧名称相同。
我的公司有数百万份 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
解释-
Split
将根据参数-
分离文件名,[-1]
告诉 PowerShell select 最后一个分离值。SubString(0,7)
将从文件BaseName
的第一个字符开始 select 7 个字符。- 删除
-WhatIf
以应用重命名。
警告:
正如 jazzdelightsme 指出的那样,如果您要从日期;例如,
2018-09-18 - ReportName.pdf
和2018-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
将不执行任何操作新名称与旧名称相同。