我正在努力编写一个Powershell命令,它可以执行以下操作。假设一个文件夹中有一堆文件,这些文件的随机名称与正则表达式模式匹配。我想捕获与模式匹配的部分,并将文件重命名为该部分。
例如,如果模式为\w\d+\w+\d+
(或类似模式),则“asdjlk-c12aa13-.pdf”应变为“c12aa13.pdf”。
我目前的想法是这样的:Get-ChildItem | Rename-Item -NewName { $_.Name -match $pattern ... } -WhatIf
个
其中...
需要替换为将代码块的“值”(即NewName)设置为匹配组的内容。即,我不知道如何在-match
命令后直接访问$matched
。
另外,我想知道是否可以使用-match
进行延迟匹配,.*?
似乎做不到这一点。
4条答案
按热度按时间k97glaaz1#
tl;dr
使用
-replace
而不是-match
在 * 单个 * 操作中匹配 * 和 * 提取感兴趣的部分,这需要您:(…)
中感兴趣的部分匹配的子表达式括起来,即 capture groups$1
引用 * 第一个 * 捕获组捕获的内容,$2
引用第二个捕获组捕获的内容,依此类推。字符串
注意事项:与您自己的代码一样,上述命令中的**
-WhatIf
公共参数*预览 * 操作**。删除-WhatIf
,并在确定操作将按您的要求执行后重新执行。请注意,不匹配正则表达式的输入文件将保持不变。
详情请继续阅读。
至于:
我想知道是否有可能使用-match进行延迟匹配,
.*?
似乎不起作用。上面使用
\b
(字边界Assert)作为延迟匹配的 * 更健壮 * 的替代方案,但.*?
原则上 * 确实 * 工作,如以下简化示例所示:型
也就是说,
.*
之后的?
确保了c
匹配被“放弃”,以便尽可能早地匹配下面的子表达式(\w\d+\w+\d+)
-转到this regex101.com page并尝试删除?
以查看行为上的差异。-replace
技术和正则表达式解释:虽然您可以在自己的尝试中遵循
-match
操作,随后通过自动$Matches
变量提取匹配的零件,但在-replace
操作符的帮助下,通常更容易 * 合并 * 这两个操作:你只需要确保为了只返回你感兴趣的部分,你必须匹配输入字符串 * 完整 *,然后忽略你不关心的部分,如下面这个简化的例子所示:
型
有关正则表达式的更详细解释和使用它的选项,请参阅this regex101.com page。
.*\b
匹配感兴趣部分之前的前缀;\b
确保以下子表达式仅在 * 单词边界 * 处匹配(即仅在字母数字1或_
之外的字符 * 处匹配)。(\w\d+\w+\d+)
匹配感兴趣的部分, Package 在捕获组中;由于它是正则表达式中的第 * 1 * 个捕获组,因此可以在替换操作数中将其捕获的内容引用为$1
。\b.*
,在一个字的边界,匹配的一切之后,直到.pdf
文件扩展名。(\.pdf)$
与名称末尾的文件扩展名.pdf
匹配,作为 2nd 捕获组,可以在替换操作数中引用为$2
。.Name
值进行操作的另一种方法是仅匹配.BaseName
属性,并在之后附加.Extension
属性,沿着行:型
$1$2
简单地连接2个capture-group匹配以输出所需的名称。$
就不会被 PowerShell 事先意外解释。-replace
和替换操作数语法的详细信息,请参见this answer。kmynzznz2#
一个更安全的方法是使用一个测试(类似于
-WhatIf
)。这个例子重命名文件从DSC12345 - X-1.jpg
=>DSC12345-X1.jpg
字符串
这是安全得多,因为重命名可以是灾难性的,当运行错误。
anauzrmj3#
你可以在脚本块中放尽可能多的东西。同时隐藏-match的输出。正则表达式对“?"是懒惰的。
字符串
vawmfj5a4#
老实说,我不确定你上面的行是否有效。如果“\w\d+\w+\d+”是你正在寻找的模式,我会这样做:
字符串
在本例中,您将Get-ChildItem的输出管道化到“foreach where循环”(?{...}),然后将此输出管道化到“foreach循环”(%{...})以重命名每个对象。