我有几千个重复的文件(以jar文件为例),我想使用PowerShell来
- 递归地搜索文件系统
- 找到副本(仅按名称或使用校验和方法或两者同时)
- 删除所有重复文件,只保留一个。
我是powershell的新手,希望能得到PS专家的帮助。
我有几千个重复的文件(以jar文件为例),我想使用PowerShell来
我是powershell的新手,希望能得到PS专家的帮助。
试着这样做:
ls *.txt -recurse | get-filehash | group -property hash | where { $_.count -gt 1 } | % { $_.group | select -skip 1 } | del
来源: http://n3wjack.net/2015/04/06/find-and-delete-duplicate-files-with-just-powershell/
$dict = @{};
dir c:\admin -Recurse | foreach {
$key = $_.Name #replace this with your checksum function
$find = $dict[$key];
if($find -ne $null) {
#current file is a duplicate
#Remove-Item -Path $_.FullName ?
}
$dict[$key] = 0; #dummy placeholder to save memory
}
我使用文件名作为键,但如果需要可以使用校验和(或两者都用)- 请参见代码注释。
即使这个问题很老,我仍然需要根据内容清理所有重复的文件。这个想法很简单,但是实现的算法并不直接。以下是一个代码示例,它接受一个参数“路径”,用于删除其中的重复文件。
Function Delete-Duplicates {
param(
[Parameter(
Mandatory=$True,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True
)]
[string[]]$PathDuplicates)
$DuplicatePaths =
Get-ChildItem $PathDuplicates |
Get-FileHash |
Group-Object -Property Hash |
Where-Object -Property Count -gt 1 |
ForEach-Object {
$_.Group.Path |
Select -First ($_.Count -1)}
$TotalCount = (Get-ChildItem $PathDuplicates).Count
Write-Warning ("You are going to delete {0} files out of {1} total. Please confirm the prompt" -f $DuplicatePaths.Count, $TotalCount)
$DuplicatePaths | Remove-Item -Confirm
}
该脚本:
a) 列出所有ChildItems
b) 从中检索FileHash
c) 按照Hash属性对它们进行分组(因此所有相同的文件都在单个组中)
d) 过滤已唯一的文件(组数 -eq 1)
e) 循环遍历每个组并列出除最后一个路径之外的所有路径-确保每个"Hash"文件总是留下一个
f) 在继续之前发出警告,说明总共有多少个文件以及将删除多少个文件。
这可能不是最高效的选项(对每个文件进行SHA1),但可以确保该文件是重复的。 对我而言,完美地运行 :)
@KaiWang的回答升级版,新版本实现:
Get-ChildItem *.ttf -Recurse |
Group -Property Length |
Where { $_.Count -gt 1 } |
ForEach { $_.Group } |
ForEach { $_ } |
Get-FileHash -Algorithm 'MD5' |
Group -Property Hash |
Where { $_.Count -gt 1 } |
ForEach {
$_.Group |
Sort -Property @{ Expression = { $_.Path.Length } } |
Select -SkipLast 1
} |
ForEach { $_.Path } |
ForEach {
Write-Host $_
Del -LiteralPath $_
}
不要仅仅删除重复的文件,你可以用快捷方式替换它们
#requires -version 3
<#
.SYNOPSIS
Script de nettoyage des doublons
.DESCRIPTION
Cherche les doublons par taille, compare leur CheckSum MD5 et les regroupes par Taille et MD5
peut remplacer chacun des doubles par un lien vers le 1er fichier, l'original
.PARAMETER Path
Chemin ou rechercher les doublon
.PARAMETER ReplaceByShortcut
si specifier alors les doublons seront remplacé
.PARAMETER MinLength
ignore les fichiers inferieure a cette taille (en Octets)
.EXAMPLE
.\Clean-Duplicate '\\dfs.adds\donnees\commun'
.EXAMPLE
recherche les doublon de 10Ko et plus
.\Clean-Duplicate '\\dfs.adds\donnees\commun' -MinLength 10000
.EXAMPLE
.\Clean-Duplicate '\\dpm1\d$\Coaxis\Logiciels' -ReplaceByShortcut
#>
[CmdletBinding()]
param (
[string]$Path = '\\Contoso.adds\share$\path\data',
[switch]$ReplaceByShortcut = $false,
[int]$MinLength = 10*1024*1024 # 10 Mo
)
$version = '1.0'
function Create-ShortCut ($ShortcutPath, $shortCutName, $Target) {
$link = "$ShortcutPath\$shortCutName.lnk"
$WshShell = New-Object -ComObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($link)
$Shortcut.TargetPath = $Target
#$Shortcut.Arguments ="shell32.dll,Control_RunDLL hotplug.dll"
#$Shortcut.IconLocation = "hotplug.dll,0"
$Shortcut.Description ="Copy Doublon"
#$Shortcut.WorkingDirectory ="C:\Windows\System32"
$Shortcut.Save()
# write-host -fore Cyan $link -nonewline; write-host -fore Red ' >> ' -nonewline; write-host -fore Yellow $Target
return $link
}
function Replace-ByShortcut {
Param(
[Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
$SameItems
)
begin{
$result = [pscustomobject][ordered]@{
Replaced = @()
Gain = 0
Count = 0
}
}
Process{
$Original = $SameItems.group[0]
foreach ($doublon in $SameItems.group) {
if ($doublon -ne $Original) {
$result.Replaced += [pscustomobject][ordered]@{
lnk = Create-Shortcut -ShortcutPath $doublon.DirectoryName -shortCutName $doublon.BaseName -Target $Original.FullName
target = $Original.FullName
size = $doublon.Length
}
$result.Gain += $doublon.Length
$result.Count++
Remove-item $doublon.FullName -force
}
}
}
End{
$result
}
}
function Get-MD5 {
param (
[Parameter(Mandatory)]
[string]$Path
)
$HashAlgorithm = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$Stream = [System.IO.File]::OpenRead($Path)
try {
$HashByteArray = $HashAlgorithm.ComputeHash($Stream)
} finally {
$Stream.Dispose()
}
return [System.BitConverter]::ToString($HashByteArray).ToLowerInvariant() -replace '-',''
}
if (-not $Path) {
if ((Get-Location).Provider.Name -ne 'FileSystem') {
Write-Error 'Specify a file system path explicitly, or change the current location to a file system path.'
return
}
$Path = (Get-Location).ProviderPath
}
$DuplicateFiles = Get-ChildItem -Path $Path -Recurse -File |
Where-Object { $_.Length -gt $MinLength } |
Group-Object -Property Length |
Where-Object { $_.Count -gt 1 } |
ForEach-Object {
$_.Group |
ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name ContentHash -Value (Get-MD5 -Path $_.FullName)
}
$_.Group |
Group-Object -Property ContentHash |
Where-Object { $_.Count -gt 1 }
}
$somme = ($DuplicateFiles.group | Measure-Object length -Sum).sum
write-host "$($DuplicateFiles.group.count) doublons, soit $($somme/1024/1024) Mo" -fore cyan
if ($ReplaceByShortcut) {
$DuplicateFiles | Replace-ByShortcut
} else {
$DuplicateFiles
}
-contains
检查就足够了,不需要字典。 - Ansgar Wiechers