ストリーミング (あと switch 文)

カレントディレクトリに以下の内容の aaa.txt があったとして、

hoge
piyo
foo
bar

このコマンドを実行するとどういう結果が得られるでしょう?

$line = 0; cat 'aaa.txt' | ?{ $line++; $_ -match 'o$' } | %{ "$line $_" }

分かりにくい場合はこちらをどぞ。

$line = 0
cat 'aaa.txt' | where { $line++; $_ -match 'o$' } | foreach { "$line $_" }

・・・って、変らないか。

1.

4 piyo
4 foo

2.

2 piyo
3 foo

回答はまだだよ!

つまり、文に書き換えた場合、出力が

$line = 0
$cat = @()
foreach ($lineStr in cat 'aaa.txt') {
  $line++
  if ($lineStr -match 'o$') {
    $cat += $lineStr
  }
}
foreach ($lineStr in $cat) {
  "$line $lineStr"
}

と同じになるか、

$line = 0
foreach ($lineStr in cat 'aaa.txt') {
  $line++
  if ($lineStr -match 'o$') {
    "$line $lineStr"
  }
}

と同じになるか、という問題です。
?{ $line++; $_ -match 'o$' } の部分が行数分実行された後で、正規表現にマッチした行が %{ "$name $line $_" } に渡されると考えると 1. になりそうなものだけど、実際には 2. になる。
これがストリーミングで、cat が一行返すごとにパイプラインを最後まで*1流れていく。
この部分が理解できれば、一つの壁を越えたことになる・・・のかな?

おまけ

PowerShell 最強の (?) switch 文を使った方法。

$line = 0
switch -regex -file 'aaa.txt' {
  'o$' { $line++; "$line $_" }
  default { $line++ }
}

switch 文・・・恐ろしい子!

*1:勿論正規表現にマッチしなければそこで止まるけど