指定した日付のファイルを探すワンライナー

昨日、今日と早起きしているbonlifeです。三日坊主で終わるのかどうか、乞うご期待。(二日坊主の可能性もあり。)
PowerShellの本、ようやくPart6まで読み終わりました。残すは多言語との連携について書かれたPart7のみ。ということで、記憶がフレッシュなうちに少し試してみることにしました。(おいおい、もっとこう書いた方が良いだろうが!的なコメントなどお待ちしております。)

[参考]

まずは練習として指定した日付のファイルを探すワンライナーを書いてみることに。色々と試してみて分かったのは、Get-Help と Get-Member あたりを駆使して調べながらチャレンジすると良い感じ。

Get-ChildItem | Get-Member | ?{$_.MemberType -eq "Property"}

例えば、こんな感じで Get-ChilItem の結果としてパイプ経由で渡されるオブジェクトの Member を調べられます。2つ目のパイプの後、? (Where) でPropertyの情報だけに絞ってみたり。
で、指定した日付のファイルを探す場合は、以下のようにすればOK(のはず)。

Get-ChildItem . -Recurse | ?{$_.GetType().Name -eq "FileInfo" -and ($_.LastWriteTime) -ge [DateTime]"2007/05/07" -and ($_.LastWriteTime) -lt [DateTime]"2007/05/08"}

ファイルだけを処理させるために、GetType().Name が"FileInfo"のオブジェクトという条件をつけて、かつ LastWriteTime が"2007/05/07"を[DateTime]型にキャストしたものより大きく、かつ LastWriteTime が(以下略)。そうそう、DateTime型へのキャストは明示的に行わなくても、比較をすると自動的にDateTime型にキャストされるので、[DateTime]は省略可能です。比較の左辺の型にキャストしてるっぽいですね。いずれにせよ、このままだとちょっと分かり辛いので少し書き直し。

Get-ChildItem . -Recurse | ?{$_.GetType().Name -eq "FileInfo"} | ?{($_.LastWriteTime).ToString("yyyyMMdd") -eq "20070507"}

変更したのは2点。-and で複数の条件を指定すると見辛いので、条件ごとにパイプを分けてみました。後、LastWriteTime で返ってくるDateTime型の値を ToString() でYYYYMMDDの文字列に変更して、文字列同士の比較に変更してみました。パフォーマンス計測してないのですが、動くので気にしないことにします。
これで目的のファイルは表示されるようになりますが、表示する内容を変更したい(取得するPropertyを変更したい)場合、以下のようにします。

Get-ChildItem . -Recurse | ?{$_.GetType().Name -eq "FileInfo"} | ?{($_.LastWriteTime).toString("yyyyMMdd") -eq "20070507"} | Select-Object FullName, LastWriteTime

上の例では、Select-Object でFileInfoオブジェクトの FullName、LastWriteTime の2つのプロパティを表示させるようにしています。
続いて、指定した日付のファイルを削除するように変更してみます。

Get-ChildItem . -Recurse | ?{$_.GetType().Name -eq "FileInfo"} | ?{($_.LastWriteTime).toString("yyyyMMdd") -eq "20070507"} | %{Remove-Item $_}

最後のパイプ以降の部分で、% (ForEach)を使ってそれぞれを Remove-Item します。これだけ。ただ、このままだと無条件にファイルが消されてしまい怖いですよね。そうでもないですか。そんな場合には、実際に削除する前に -WhatIf をつけて確認すれば安心、安心です。

Get-ChildItem . -Recurse | ?{$_.GetType().Name -eq "FileInfo"} | ?{($_.LastWriteTime).toString("yyyyMMdd") -eq "20070507"} | %{Remove-Item $_ -WhatIf}

こうすると -WhatIf をつけなかった場合に処理する内容を表示します。上記の場合、このファイルとこのファイルを削除しますよ!的なメッセージが出るだけで、実際には削除しません。

Get-ChildItem . -Recurse | ?{$_.GetType().Name -eq "FileInfo"} | ?{($_.LastWriteTime).toString("yyyyMMdd") -eq "20070507"} | %{Remove-Item $_ -Confirm}

こんな風に -Confirm を指定して1つずつ削除するかどうかを確認しながら処理することもできます。ファイル数(というより対象とするオブジェクトの数)が多い場合にはちょっと面倒ですが。
PowerShell、触り始めたばかりですが、なかなかに魅力的。パイプ経由に渡すのが文字列じゃなくてオブジェクトってのがやっぱり素敵っぽいです。素直にそのオブジェクトのMethodやPropertyを使えるのがナイスです。気が向いたら、またちょくちょくPowerShellを使ってみようと思います。

Windows PowerShell宣言! (Windows Script Programming)

Windows PowerShell宣言! (Windows Script Programming)