貝殻本でPowerShellの勉強をしよう@パイプライン編

一部界隈で話題になったPowerShellの貝殻本こと『PowerShell実践ガイドブック』を、通勤電車に乗っている間等の隙間時間を使ってななめ読みを少しずつしています。
現在第二章の途中というところまできました。
電車に乗っている間ということもあり、読みながら手を動かすのは難しいですが、今読み進めている範囲では基本を中心に紹介されているということもあり、実際に手を動かさないでも大体の動きは分かるので問題ないのです。
ただ、パイプラインの紹介をされているところを読んでいて少し気になったことがあったので、ちょっとお勉強がてらお手手を動かしてみようかと思います。

先日、PowerShellで拡張子”.jpg”のファイルのみをフォルダAからフォルダBにコピーするという単純なコードを書いた際、最初以下を実行しエラー発生したため、軽く首を傾げていました。

ls "folderA" -Recurse | ?{$_.Extension -match ".jpg"} | cp $_ "folderB"

最初、”$_”と記載している部分が上手くファイルパスを受け渡ししてくれていないのかとも思っていたのですが、貝殻本のパイプラインの仕様を読むとどうやらそうじゃないらしいことが書いてあるで確認してみました。

まず、”cp”こと”Copy-Item”コマンドレットの移行元ファイルのパス指定に使われる”Path”オプションの型を確認してみたところ、”string[]”とのこと。
これは感覚的にもそんな感じがしていたので納得。

PS > help Copy-Item -Full

-Path <string[]>
    必須                         true
    位置                         0
    パイプライン入力を許可する   true (ByValue, ByPropertyName)
    パラメーター セット名           Path
    エイリアス                      なし
    動的                     false

じゃあ、入力元の”ls”こと”Get-ChildItem”の出力するオブジェクトの型はというと”System.IO.DirectoryInfo”でした。

PS > Get-ChildItem |Get-Member
TypeName: System.IO.DirectoryInfo

これを見て、ああ確かにこれじゃあ無理だ、ということで書き直し。
ついでにもう少しPowerShellらしいコードに、ということでこんな感じでドン!

ls "folderA" -Filter *.txt -Recurse | cp -path { [string]$_.fullname } "folderB"

イイ感じにPowerShellらしくなったのではないでしょうか。
個人的に喉に小骨が刺さっているかのような気持ち悪さが解決できて非常に満足です。

これまでPowerShellでコードを書く際、パイプラインの動きについては感覚的に書いていたところもあり、貝殻本のパイプラインの紹介は自分自身の感覚の裏付けと、今まで面倒と思ってあまり深く突っ込まなかった部分の知識の補完となっていて、読んでいて楽しいです。
というか、今まで自分が如何に”Get-Help”コマンドレットを使っていないか、そのせいで無駄に遠回りしていたかが分かって反省しきりです(笑

ちなみに、最初に記載していた失敗例ですが、そのときは最終的に以下のように対応しました。

ls "folderA" -Recurse | ?{$_.Extension -match ".jpg"} | %{cp $_.fullname "folderB"}

わざわざforeachしていたりする強引なコードになってしまっていて、強引な感じがするのであまり書きたくない感じです。
ちゃんと仕様を理解してキレイなコードを書けるように心がけたいですね。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です