共用方式為


パイプラインのオブジェクトをのぞき見する

まずはスクリプトそのものから。

 function Watch-PipeLine {

  param (
    [Parameter(Mandatory=$true)]
    [ScriptBlock] $ScriptBlock,
    [Parameter(Mandatory=$true,ValueFromPipeLine=$true)]
    [PSObject] $Object
  )

  process {
    $Object | Foreach $ScriptBlock
    $Object
  }

}

New-Alias Watch Watch-PipeLine 

これを使うと、パイプラインを流れるオブジェクトを簡単にのぞき見できます。たとえば以下のようなファイル名の一覧を取得している処理があったとしましょう。

 $logFiles = dir -Recurse Logs |
 Where PSIsContainer -eq $false |
 Foreach Name |
 Sort-Object

ここでファイルサイズを合計もとりたいという要望があったので、以下のように書き換えたとします。

 $total = 0

$logFiles = dir -Recurse Logs |
 Where PSIsContainer -eq $false |
 Foreach {
   $total += $_.Length
   $_.Name
 } |
 Sort-Object

これで問題はまったくないのですが、パイプラインの流れがちょっとみづらくなりました。Foreach のところで最終的に $_.Name を emit していることが読み取りやすいかどうかがポイントです。ここで、上記の Watch-PipeLine を用いると、以下のように書き換えることができます。

 $total = 0

$logFiles = dir -Recurse Logs |
 Where PSIsContainer -eq $false |
 Watch { $total += $_.Length } |
 Foreach Name |
 Sort-Object

パイプラインの各段の処理にはまったく手をいれておらず、Watch の一行を追加しただけです。Watch はパイプラインの値をのぞき見して何か処理をしている、ということがわかっているので、パイプラインのメインの流れをみるうえでは Watch の部分を気にする必要はありません。

実のところ、ここで用いた Watch は以下のような Foreach  と等価です。

 Foreach { $total += $_.Length; $_ }

これで十分なのでは、という話もあるんですが、これはこれで最後の $_ を付け忘れたりすることがあります。

というか付け忘れたので、こういう案をひとつ思いついた、というエントリでした。