* 2つのフォルダ内を比較する - PowerShell [#q9cba995]

** 目的・前提 [#gedb561b]

- 2つのフォルダ内にあるファイル群のうち、異なっているファイルを抜き出す。
- 異なっているとは、1)ファイル名が違うか、ファイル名が同じでも、2)ファイルサイズが違う、3)最終更新日時が違うを条件とする。
- テキストファイルの中身の比較を細かに行いたい場合はWinMergeのような比較ツールを使う、複雑な比較条件を設定したい場合はプログラミングしてツールを自作した方がよいだろうが、簡単な比較であれば以下のようにWindows標準のPowerShellだけでも事足りる。
- 今回は "dir1" と "dir2"という2つのフォルダ内のファイル群を比較することとする。以下で紹介するフォルダ名は自分の環境に合わせて読み替えること。

** 更新日時が直近10件を抜き出す(サブディレクトリを含める) [#q649e909]

 PS> dir -r dir1 -File | sort LastWriteTime -Descending | select -First 10 FullName, FileSize, LastWriteTime
 PS> dir -r dir2 -File | sort LastWriteTime -Descending | select -First 10 FullName, FileSize, LastWriteTime
 
  FullName            FileSize LastWriteTime
 --------            -------- -------------
 C:\temp\dir1\3.txt   10 B   2018/05/05 13:53:24
 C:\temp\dir1\2.txt    5 B   2018/05/05 10:10:05
 C:\temp\dir1\1.txt   11 B   2018/05/04 09:40:34

- 上のコマンドをそれぞれのフォルダごとに実行する。
- ファイルのフルパスとファイルサイズ、最終更新日時がリストアップされるので、見覚えのあるファイルがないか、検討してみる。
- 変更したファイルが大量にあったり、まったく知らないファイル群を比較する場合はこの方法ではあまり役に立たないだろうが、
- 最近いくつかファイルを更新した、あるいはいくつかファイルを追加・削除したがどのファイルだったか忘れた、というシチュエーションの場合、このコマンドだけで問題は解決すると思う。
- 最近いくつかファイルを更新したあるいはいくつかファイルを追加・削除したが、どのファイルだったか忘れた、というシチュエーションの場合、このコマンドだけで問題は解決すると思う。


** ファイル名で比較する(サブディレクトリを含めない) [#haf9699a]

 PS> $d1 = gci dir1
 PS> $d2 = gci dir2
 PS> compare $d1 $d2 -passthru | select fullname
 
  FullName
 --------
 C:\temp\dir2\4.txt
 C:\temp\dir1\2.txt

- フォルダ内にファイルが大量にあって、最近追加された、あるいは削除されたファイルがどれだかすぐには分からない場合にこの方法を使う。
- 上の例ではdir1に2.txtがあるが、dir2にはない。dir2に4.txtがあるが、dir1にはない。という状況を表している。必要に応じて、それぞれのフォルダからファイルをコピーペーストしてあげればいい。
- ただし、フォルダ内のフォルダ(サブディレクトリ)以下のファイルについては検証しない。
- また、この方法はファイルの中身は検証しないので、ファイルが書き換わっていても抽出されない。

** ファイル名他で比較する(サブディレクトリを含める) [#rfe4f16c]

*** ファイル名とファイルサイズで比較する [#y1de2f1a]

 PS> $map1 = @{}; cd dir1; dir -r -file | % { $p = Resolve-Path -Relative $_.FullName; $map1[$p] = $_.Length }; cd ..
 PS> $map2 = @{}; cd dir2; dir -r -file | % { $p = Resolve-Path -Relative $_.FullName; $map2[$p] = $_.Length }; cd ..
 PS> $map1.Keys + $map2.Keys | ? { $map1[$_] -ne $map2[$_] } | `
        % { if (!$map1.containskey($_)) { "2 only: " + $_ } `
        elseif (!$map2.containskey($_)) { "1 only: " + $_ } else { "differ: " + $_ } } | sort | gu
 
 1 only: .\A\20.txt
 2 only: .\4.txt
 differ: .\2.txt

- dir1とdir2に対して、相対ファイルパス名をキーに、そのファイルサイズを値にしたハッシュを$map1、$map2に作って、比較している。
- 上の例ではdir1以下だけにA\20.txtが存在している。dir2以下だけに4.txtが存在している。2.txtはdir1とdir2で内容(ファイルサイズ)が違うという状況を表している。
- ほとんどの場合、ファイルを書き換えた場合はファイルサイズが異なるので、この方法で十分だと思う。心配な場合は下の方法で更新日時も条件に加えるとよい。
- なお、行末の`(バッククォート)は行の折り返しのためなので改行しないなら入力しないでいい。

*** ファイル名とファイルサイズと更新日時で比較する [#k1a4a9c2]

 PS> $map1 = @{}; cd dir1; dir -r -file | % { $p = Resolve-Path -Relative $_.FullName; $map1[$p] = ($p,$_.LastWriteTime,$_.Length) -join "," }; cd ..
 PS> $map2 = @{}; cd dir2; dir -r -file | % { $p = Resolve-Path -Relative $_.FullName; $map2[$p] = ($p,$_.LastWriteTime,$_.Length) -join "," }; cd ..
 PS> $map1.Keys + $map2.Keys | ? { $map1[$_] -ne $map2[$_] } | `
   % { if (!$map1.containskey($_)) { "2 only: " + $_ } elseif (!$map2.containskey($_)) { "1 only: " + $_ } else { "differ: " + $_ } } | `
   sort | gu
 PS> $map1.Keys + $map2.Keys | ? { $map1[$_] -ne $map2[$_] }

- この方法でほぼ間違いなく抜き出せると思うが、それでも心配ならWinMergeをインストールして使うといい。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS