在Powershell中将文件重命名为小写

30

我试图使用PowerShell 2.0递归地重命名一堆文件。目录结构如下:

Leaflets
+ HTML
  - File1
  - File2
  ...
+ HTMLICONS
  + IMAGES
    - Image1
    - Image2
  - File1
  - File2
  ...
+ RTF
  - File1
  - File2
  ...
+ SGML
  - File1
  - File2
  ...

我正在使用以下命令:

get-childitem Leaflets -recurse | rename -newname { $_.name.ToLower() }

看起来它已经重命名了文件,但是对于子目录会有投诉:

Rename-Item : Source and destination path must be different.
我每月使用robocopy重新加载数据,但是目录不会改变,所以我可以手动重命名它们。有没有办法让get-children跳过子目录(就像find Leaflets -type f ...这样)?
谢谢。
更新:看起来问题出在已经全部小写的文件上。我尝试将命令更改为:
get-childitem Leaflets -recurse | if ($_.name -ne $_name.ToLower()) rename -newname { $_.name.ToLower() }

但现在 PowerShell 报错,显示 if 不是 cmdlet、函数等。我能将 get-childitem 的输出管道到 if 语句中吗?

更新2: 这个方法可行:

$files=get-childitem Leaflets -recurse
foreach ($file in $files)
{
    if ($file.name -ne $file.name.ToLower())
    {
        rename -newname { $_.name.ToLower() }
    }
}

在 PowerShell 7 中,如果新名称与旧名称相同,Rename-Item 至少不会出错。但我不确定这种行为是从哪个版本开始改变的。但你第一次尝试将 gci 管道传递到 rename-item 现在可以工作了。 - codewario
9个回答

36

虽然您已经发布了自己的答案,但这里有一种变化:

dir Leaflets -r | % { if ($_.Name -cne $_.Name.ToLower()) { ren $_.FullName $_.Name.ToLower() } }

一些要点:

  • dirGet-ChildItem 的别名(而 -r 则是 -Recurse 的简写)。
  • %ForEach-Object 的别名。
  • -cne 表示区分大小写的比较,-ne 则忽略大小写差异。
  • $_ 是在 ForEach-Object 循环中引用当前项的方式。
  • renRename-Item 的别名。
  • FullName 可能更受欢迎,因为它确保您将操作正确的文件。

如果您想排除要重命名的目录,可以添加以下内容:

if ((! $_.IsPsContainer) -and $_.Name -cne $_.Name.ToLower()) { ... }

希望这有助于继续学习和探索PowerShell。


4
值得一提的是,这适用于重命名文件而非目录。对于目录来说,你需要进行2个重命名操作。参见此处获取一个示例。 - velsietis

20

请记住,您可以直接将管道连接到Rename-Item并使用脚本块与 -NewName 参数一起使用(因为它也接受管道输入),以简化此任务:

Get-ChildItem -r | Where {!$_.PSIsContainer} | 
                   Rename-Item -NewName {$_.FullName.ToLower()}

并且使用别名:

gci -r | ?{!$_.PSIsContainer} | rni -New {$_.FullName.ToLower()}

谢谢。我们可以使用以下命令更改文件名: gci . -recurse -force | ?{!$.PSIsContainer} | rni -New {$.Name.replace("aaa","bbb")} - Mahmoud Moravej

3

由于 Rename-Item、管道、循环和Windows文件系统的工作方式,之前给出的答案存在许多问题。不幸的是,我找到的最简单(在此处不使用别名以提高可读性)将给定文件夹中的所有文件和文件夹重命名为小写字母的解决方案是这样的:

Get-ChildItem -Path "/Path/To/You/Folder" -Recurse | Where{ $_.Name -cne $_.Name.ToLower() } | ForEach-Object { $tn="$($_.Name)-temp"; $tfn="$($_.FullName)-temp"; $nn=$_.Name.ToLower(); Rename-Item -Path $_.FullName -NewName $tn; Rename-Item -Path $tfn -NewName $nn -Force; Write-Host "New Name: $($nn)";}

我用这个工具来重命名几百万个文件 - 但有一个问题是它无法处理带有方括号 '[' 或 ']' 的文件。我认为这里有一个解决方案。我没有尝试修复,因为我有一个后续处理方法,而且这个工具已经解决了大部分问题。 - Logan Waggoner
你可能还需要将文件夹名称转换为小写 - 可以从你正在工作的根目录运行类似这样的命令: #获取目录/子目录并重命名为小写 Get-ChildItem -recurse| ?{ $_.PSIsContainer -And $_.Name -CMatch "[A-Z]" } | %{ $NName = $_.Name.ToLower() #设置临时名称以便将其重命名为相同的名称;Windows不区分大小写 $TempItem = Rename-Item -Path $_.FullName -NewName "x$NName" -PassThru Rename-Item -Path $TempItem.FullName -NewName $NName } - Logan Waggoner
应该使用Rename-Item -LiteralPath而不是-Path,因为某些文件类型不受支持(否则会出现括号等问题)。 - Logan Waggoner

2
稍微调整一下,如果你只想更新特定类型文件的名称,请尝试以下操作:
get-childitem *.jpg | foreach { if ($_.Name -cne $_.Name.ToLower()) { ren $_.FullName $_.Name.ToLower() } }

这将只会将文件夹中的jpg文件转换为小写字母,而忽略其他文件。


2

您需要将它们暂时更名为其他名称,然后重新命名为全小写字母。

$items = get-childitem -Directory -Recurse

foreach ($item in $items)
{

   if ($item.name -eq $item.name.ToLower())
   {    

       $temp = $item.FullName.ToLower() + "_"
       $name = $item.FullName.ToLower()
       ren $name $temp

       ren $temp $name
   }

0

对于所有关注此线程的人;以下一行代码也可用于降低文件和目录。

Get-ChildItem -r  | Rename-Item -NewName { $_.Name.ToLower().Insert(0,'_') } -PassThru |  Rename-Item -NewName { $_.Name.Substring(1) }

主帖:https://dev59.com/VMPra4cB1Zd3GeqPbTgM#70559621


0

在 PowerShell 中,使用 where 而不是 if 更符合惯用语:

gci -Recurse Leaflets | 
    ? { $_.Name -ne $_.Name.ToLower()) } | 
    % { ren -NewName $_.Name.ToLower() }

0
对于Jay Bazuzi的答案,有一个小但重要的更正。如果where部分需要返回任何内容,则必须使用-cne(区分大小写不相等)运算符。
此外,我发现需要存在Path参数。这个版本在我的设置中有效:
gci -Recurse | 
    ? { $_.Name -cne $_.Name.ToLower() } | 
    % { ren $_.Name -NewName $_.Name.Tolower()  }

0
修改以便与名称中的[]括号或其他不支持的字符一起使用,并且还将处理目录(或者您可以省略此部分)。我从各个地方拼凑而成。
应该能够将此放入一个文件中,然后导航到目标目录并从那里运行它。
#Get the directories / sub directories and rename to lowercase 
Get-ChildItem -recurse| ?{ $_.PSIsContainer -And $_.Name -CMatch "[A-Z]" } | %{ 
$NName = $_.Name.ToLower() 
#Set temporary name to enable rename to the same name; Windows is not case sensitive 
$TempItem = Rename-Item -LiteralPath $_.FullName -NewName "x$NName" -PassThru Rename-Item -LiteralPath $TempItem.FullName -NewName $NName }

#Now handle all the files
Get-ChildItem -LiteralPath . -Recurse | Where{ $_.Name -cne $_.Name.ToLower() } | ForEach-Object { 
$tn="$($_.Name)-temp"; $tfn="$($_.FullName)-temp"; 
$nn=$_.Name.ToLower(); 
Rename-Item -LiteralPath $_.FullName -NewName $tn; 
Rename-Item -LiteralPath $tfn -NewName $nn -Force; 
Write-Host "New Name: $($nn)";
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接