標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

PowerShell で、二つのフォルダーのファイル構成を比較するコマンドを作る

dirdiff.cmd

@set "arg1=%~1" & set "arg2=%~2"
@powershell "iex((@('','','')+(cat '%~f0' | select -skip 3))-join[char]10)"
@exit /b %ERRORLEVEL%

$md5 = New-Object System.Security.Cryptography.MD5CryptoServiceProvider

function Get-MD5s($dir){
    $md5s = @{}
    Get-ChildItem $dir |
    Where-Object { $_.Mode[0] -ne "d" } |
    ForEach-Object {
        $data = [System.IO.File]::ReadAllBytes($_.FullName)
        $bs = $md5.ComputeHash($data)
        $md5s[ $_.Name ] = `
            ([System.BitConverter]::ToString($bs).ToLower() -replace "-","")
    }
    return $md5s
}

$dir1 = $env:arg1
$dir2 = $env:arg2

$hash1 = (Get-MD5s $dir1)
$hash2 = (Get-MD5s $dir2)

foreach($p in $hash1.Keys){
    if( $hash2.ContainsKey($p) ){
        $private:val1 = $hash1[$p]
        $private:val2 = $hash2[$p]
        if( $val1 -ne $val2 ){
            Write-Output ("{0} differ" -f $p)
            Write-Output ("  {0} {1}" -f $val1,(Join-Path $dir1 $p))
            Write-Output ("  {0} {1}" -f $val2,(Join-Path $dir2 $p))
        }else{
            Write-Verbose ("{0} same" -f $p)
        }
    }else{
        Write-Output ("{0} not found" -f (Join-Path $dir2 $p))
    }
}

foreach($p in $hash2.Keys){
    if( -not $hash1.ContainsKey($p) ){
        Write-Output ("{0} not found" -f (Join-Path $dir1 $p))
    }
}

# vim:set ft=ps1:
  • 最初の3行は、PowerShell をバッチファイル化するためのまじない
  • 二つのディレクトリの直下にあるファイルの md5連想配列に格納して、比較するだけ

こういうのは別のバッチファイルから呼び出したいから、Goで作った方がいいな…と後から思いました。まる

追記

Goで作ってみました。https://github.com/zetamatta/experimental/blob/master/dirdiff/main.go