Where-Objectのスクリプトブロックで複数の文を使いたいとき
へえこんなふうになるんだ
> 1..3 | ?{ $_ % 2 } 1 3 > 1..3 | ?{ $false } > 1..3 | ?{ $true } 1 2 3 > 1..3 | ?{ $false; $false } # 注目 1 2 3
whereのスクリプトブロックで複数の文使えない!?
おさらい。where-objectの{ }は、フィルタースクリプトと書いてあるように、真偽値を返すスクリプトブロックである。
Where-Object [-FilterScript] <scriptblock> [-InputObject <psobject>] [<CommonParameters>]
ってことでスクリプトブロックの評価について調べてみた
> (&{ $false; $false }).GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Object[] System.Array > (&{ $false; }).GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Boolean System.ValueType > [bool](&{ $false; $false }) True
なるほど、?{ $false; $false }だと、@($false, $false)という配列になってTrueと判定されるみたい
ちなみに配列を真偽値に変換すると?
> [bool] @() False > [bool] @($false) False > [bool] @($true) True > [bool] @($false, $false) True
なるほど、複数の要素がある配列だとTrueなのかな?だから、?{ $false; $false }だとTrueになると。
では、こうしたい時はどうすればよいか?ファイル名末尾の番号が235以上のものを取得したい。
> gci -file | ?{ $_.Name -match "\d+$"; [int]$matches[0] -ge 235 } # スクリプトブロックがTrueになるので、全ファイルが取得されてしまう!
and演算子を使えばうまくいった
> gci -file | ?{ ($_.Name -match "\d+$") -and ([int]$matches[0] -ge 235) }
()内部が式ではなく文のときもandでうまくいくかは謎だし、andの前の項がTrueを返さないといけなくて微妙
これでもうまくいった。こっちのほうがいいかも
> gci -file | ?{ $( $_.Name -match "\d+$"; [int]$matches[0] -ge 235 )[1] }
$()による部分式は内部で複数の値を返すときに配列になる。たくさんの文を含むときは$(...)[-1}とすれば文の数を数えずに済む
追記5/3 16:25
void型にキャストすれば明示的にコマンドラインの結果を破棄できると知った
> 1..3 | ?{ [void]$false; $_ % 2 } 1 3 > @( "a"; [void]"b"; "c" ) a c
これを使って次のようにすればうまくいった。文全体をvoidでキャストする点に注意
> gci -file | ?{ [void]($_.Name -match "\d+$"); [int]$matches[0] -ge 235 }
しかし、たくさんの文を含むときはいちいち[void]するのが面倒そうなので、やはり$(...)[-1]の方法も覚えておきたい
反射的にワンライナーを書きたい
# 通し番号の十の位が1のファイルの名前を列挙 gci | ? name -like "*1?" | % name
うーん。まだまだ立ち止まって考えるレベル〜ゆっくり打ちながら考えるレベルだなぁ
ポケットリファレンス購入
CodeZineの記事読破。 http://codezine.jp/author/515 全部自分でサンプルプログラム考えて書いたら基礎力になった気がする。
ただし、Active Directory, Oracleは分からないのでパス。
さて次は?ってことで好評なポケットリファレンス購入。片っ端からサンプルプログラム自作するだけでかなり力がつきそう。500ページ以上もある。これで当分は学習のネタに困らない。
ちなみにGoogleブックスで第1章丸ごと読める。
http://books.google.co.jp/books?id=g_iCgzSrv8YC&printsec=frontcover#v=onepage&q&f=false
あと、昔買って本棚の肥やしになっていた『PowerShellインアクション』も今火を吹く!かも
他にも学習ネタはたくさん候補がある。脳内整理もかねてメモ。
基礎文法最速マスター、および他の記事
http://winscript.jp/powershell/202
まだ読んでなかったので
マイナビの記事
http://news.mynavi.jp/author/0000584/
今読んでる
PowerShell from Japan!!
http://blog.powershell-from.jp/
まず入門カテゴリから
AdventCalendar2011-2013
http://atnd.org/events/22073
http://atnd.org/events/34319
http://atnd.org/events/45107
分量多いしいろんな人が書いてるから参考になりそう
TechNetスクリプトセンター
http://gallery.technet.microsoft.com/scriptcenter/site/search?f%5B0%5D.Type=ProgrammingLanguage&f%5B0%5D.Value=PowerShell&f%5B0%5D.Text=PowerShell
実用的な例たくさん
Functionプロバイダかっけえ
Functionプロバイダで存在する関数の情報にアクセスできる
たとえば、
> function Foo(){ "test" }
って関数を定義して、
> gci function: | ?{ $_.Name -eq "Foo" } | fl -property *
で
PSPath : Microsoft.PowerShell.Core\Function::Foo PSDrive : Function PSProvider : Microsoft.PowerShell.Core\Function PSIsContainer : False HelpUri : ScriptBlock : "test" CmdletBinding : False DefaultParameterSet : Definition : "test" Options : None Description : Verb : Noun : HelpFile : OutputType : {} Name : Foo CommandType : Function Visibility : Public ModuleName : Module : RemotingCapability : PowerShell Parameters : {} ParameterSets : {}
こうなる。
このgci、要はファイルシステムのlsコマンドと同じでしょと思ってたら、任意のプロバイダを想定してたのか。この抽象化面白い。
Aliasプロバイダ、Certificateプロバイダ(デジタル証明書?)、Environmentプロバイダ(環境変数)、FileSystemプロバイダ、
Functionプロバイダ、Registryプロバイダ、Variableプロバイダもあるよ!
FileSystemだと
PS E:\Documents > cd c:\hoge\fuga PS C:\hoge\fuga >
とするのと同様、Registryプロバイダだと
PS E:\Documents > cd HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer PS HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer>
こうできる。続けざまに、
PS HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer> gci | %{ $_.PSChildName } Advanced AppContract AutoplayHandlers BitBucket CabinetState ... VisualEffects Wallpaper Wallpapers WordWheelQuery SessionInfo
とレジストリのサブキーを調べたり、
PS HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer> gp . ExplorerStartupTraceRecorded : 1 ShellState : {36, 0, 0, 0...} UserSignedIn : 1 SIDUpdatedOnLibraries : 1 ... PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\Current Version PSChildName : Explorer PSDrive : HKCU PSProvider : Microsoft.PowerShell.Core\Registry
とレジストリのエントリを調べたりできる
F2キー便利
たとえば
> Get-PSBreakpoint -Script s1.ps1
を実行してから
> Get-PSBreakpoint -Script s2.ps1
を実行したい。
ここで、F2キーを押すと
入力文字の前までコピー:
という表示がでて
1
を入力すると
> Get-PSBreakpoint -Script s
と入力されるので、あとは
2.ps1
を入力するだけで
> Get-PSBreakpoint -Script s2.ps1
になる。
http://technet.microsoft.com/ja-jp/scriptcenter/powershell_owner03.aspx
プロファイルでエイリアスの記述された行を表示
PowerShellガンガン学習中。
$lines = gc $profile | ? { $_ -match "^sal|^Set-Alias" } echo $lines
これがSelect-Stringなら・・・
sls "^sal|^Set-Alias" $profile
こう書ける。
メリットは
・既製のもので短く書ける
・行数表示してくれる
・Contextパラメータで前後の行表示してくれたりする
うーむ、それにしてもPowerShellがスーパーpre記法に未対応なのは残念。