自動でファイルを生成するスクリプトを動かした時、しばしば内容が重複する無駄なファイルを作ってしまう場合があります。そういった際などに使える、内容が重複したファイルを削除するスクリプトを紹介します。実際のコードが次です。
param( # 引数でディレクトリパスが渡されない場合はスクリプトファイル自身のディレクトリを取得 [string]$directoryPath = $(Split-Path -Parent $MyInvocation.MyCommand.Definition) ) # ディレクトリ配下の全ファイルを再帰的に読み込む $files = Get-ChildItem -Path $directoryPath -Recurse -File # ハッシュテーブルを用いる。ここにファイルの内容をハッシュ化して格納する $hashTable = @{} foreach ($file in $files) { # ファイルの内容についてのハッシュ値を取得 $hash = Get-FileHash $file.FullName -Algorithm SHA256 # 得られたハッシュ値がハッシュテーブルのキーに既に存在するかチェック if ($hashTable.ContainsKey($hash.Hash)) { # ハッシュ値が既にに存在する場合、ゴミ箱に移動 $existingFile = $hashTable[$hash.Hash] [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($file.FullName, 'OnlyErrorDialogs', 'SendToRecycleBin') Write-Host $file.FullName } else { # 存在しない場合、ハッシュテーブルにハッシュ値とファイルのパスのペアを追加 $hashTable[$hash.Hash] = $file.FullName } }
使い方は削除したいファイル群のディレクトリにこのファイル(仮にremove.ps1とします)を置いてremove.ps1
とするかremove.ps1 [削除したいファイル群のあるディレクトリのフルパス]
とするかです。
コードはファイルの内容そのものを保持するのではなくハッシュ値にし、それのテーブルを使うのがポイントです。ファイルの内容をそのまま保持するとメモリに優しくなく、全く保持せず毎回すべてのファイル内容を読むと実行速度が遅くなってしまいます。
PoweShell備え付けのRemove-Item
を使っているのではなく[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile
を使っている理由は、完全な削除ではなくゴミ箱送りにしたいからです。確認メッセージ無しの手軽な削除かつ巻き戻しが効くという点でゴミ箱送りは便利な方法です。