PowerShellの文字列フォーマット変換はPythonと似ているかも

遅寝早起きでちょっとグッタリしているbonlifeです。
PowerShellでは Format-List、 Format-Table などを使って様々な出力が出来ますが、自分の思い通りの出力をしたい時もありますよね。そんな時には文字列をフォーマットする魔法の -F です。Pythonでのモジュロ演算子を使った文字列フォーマット変換とよく似ている気がします。きっと気のせいです。
とりあえず、メモリを多く使っているプロセスTOP10を出力するワンライナーを書いてみました。

Get-Process | Sort-Object PagedMemorySize -Descending | Select-Object -First 10 | %{" {0,-20}:{1,10:#,###.0} MB" -F $_.ProcessName, ($_.PagedMemorySize/1MB)}

出力は以下のような感じです。

 firefox             :      81.2 MB
 powershell          :      28.9 MB
 svchost             :      23.1 MB
 fenrir              :      18.8 MB
 vmserverdWin32      :      15.4 MB
 B2                  :      14.2 MB
 explorer            :      13.4 MB
 winlogon            :       7.1 MB
 sbmgrnt             :       6.4 MB
 answers             :       6.1 MB

powershell、たいしたことしてないのに30MB弱も使ってるのかぁ…、あ、VMware使ってるつもりなかったのにプロセス立ち上がって15MBも使ってる!answersの英英辞書なんて使ってないよなぁ…なんて分析は置いておいて。ワンライナーの最後のパイプ以降にご注目。ExcelとかVB.NET Frameworkに慣れている人にはだいたい分かりそうな型の書式設定を使ってます。中括弧を使った書式設定は違和感がありますが、慣れの問題ですね、きっと。

[参考]

そうそう、最後の部分で ($_.PagedMemorySize/1MB) としてますが、MBは特別な意味を持っています。前に数字が来た場合、1048576 を意味する定数みたいに扱われるっぽいです。KB、GBも同様にそれぞれ 1024、1074790400 として計算に使われます。以下のような感じです。

PS C:\test> 1KB
1024
PS C:\test> 1MB
1048576
PS C:\test> 1GB
1073741824
PS C:\test> 3KB
3072
PS C:\test> 1MB + 1GB
1074790400

GBは 1024 * 1024 * 1024 で…とか意識せずに気軽に変換できて便利のような、そうでもないような。
そうそう、このあたりの情報を調べてみたら、id:newpopsさんのところに全部載ってました。この人、あの本書いてる人なんですね。なるほど、なるほどです。勉強になります。

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

昨日、今日と早起きしている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)