Powershell-递归重命名文件,添加上层文件夹作为NewName的前缀



我有这种树文件夹结构:

c:Loc_2636820220801.csv
c:Loc_2636620220607.csv
c:Loc_2538720220701.csv

我想在任何文件中添加"upper"的后缀;Loc_*";文件夹最后他们应该是这样的:

c:Loc_26368Loc_2636_20220801.csv
c:Loc_25387Loc_2538_20220701.csv

我以为这很简单,但我遇到了麻烦,因为如果我这样做:

Get-ChildItem -File -Recurse  | % { Rename-Item -Path $_.PSPath -NewName $_.FullName.Split("")[5]+"_"+$_.Name -WhatIf} 

出现此错误:找不到接受参数"+_+2020701.csv.Name"的位置参数。

相反,如果我试图通过功能来做到这一点

function rena(){
param ([string]$name, [string]$fullpath)
$arr=$fullpath.Split("")
foreach($tmp in $arr)
{
if($tmp.ToString().Contains("Loc_")){
$found=$tmp;
}
}
return $found+"_"+$name
}
Get-ChildItem -File -Recurse  | % { Rename-Item -Path $_.PSPath -NewName {rena($_.Name,$_.FullName) -WhatIf}} 

出现另一个错误

无法计算参数"NewName",因为它的参数被指定为脚本块,并且没有输入。没有输入就无法评估脚本块

我很困惑,因为我已经在Get-ChildItem命令中使用了函数,但我从未遇到过这个错误。

提前感谢您的帮助。

您可以像下面这样做:

Get-ChildItem -File -Recurse | Where-Object { $_.DirectoryName -match '\(Loc_d+)' } | 
Rename-Item -NewName { '{0}_{1}' -f $matches[1], $_.Name } -WhatIf

如果控制台中显示的内容正常,请删除-WhatIf开关。然后再次运行以实际开始重命名文件。

要防止重命名已重命名的文件(当运行多次时(,请将Where Object子句扩展到Where-Object { $_.DirectoryName -match '\(Loc_d+)' -and $_.Name -notlike 'Loc_*' }

Theo的有用答案为您的任务提供了更好的解决方案,绕过了您的语法问题。


至于您尝试的问题

为了表达式(例如,$_.FullName.Split("")[5]+"_"+$_.Name(或命令调用(例如rena $_.Name $_.FullName(作为参数传递给命令,必须把它们封装在分组运算符(...)中。

  • 虽然简单的表达式在隔离中(例如,$foo$foo.Bar$foo.ToUpper()(不需要(...),但任何更复杂的表达式都需要。

    • 关于如何在(...)被解析为自变量,请参阅此答案
  • { ... }中封装一个参数会创建一个脚本块——一段可重复使用的代码,用于按需调用;该代码不是立即执行的,所以它不是(...)的替代品(如果您将脚本blocck传递给[string]类型的参数,您将获得其逐字逐句的内容,没有{}(。然而,脚本块作为参数对于基于管道输入动态计算参数值非常有用,使用了一种名为延迟绑定脚本块的技术,如Theo的回答所示。

最后,请注意,我已经将您的函数调用从
rena($_.Name,$_.FullName)重新表述为
rena $_.Name $_.FullName,因为只有后者按预期工作:

  • PowerShell命令-函数、cmdlet、脚本和外部程序必须像shell命令-foo arg1 arg2-那样调用,而不是像C#方法-foo('arg1', 'arg2')那样调用
  • 也就是说,参数列表周围没有(...),并且空白而不是,来分隔参数。
    • 如果使用,分隔参数,您将构造一个数组,命令将其视为单个参数
  • 有关详细信息,请参阅此答案

最新更新