PowerShell 7 からPipeline Chain Operators(&& と ||)が使える様になります

PowerShell Core

しばたです。
先日リリースされたPowerShell 7 Preview.5からPipeline Chain Operators(&&||)が使える様になったので簡単にですが解説します。

Pipeline Chain Operators

以前からBash等のシェルでは&&||は複数コマンドの連続実行のために存在しており、これとほぼ同等の機能がPowerShellにも導入された形となります。

PowerShellではRFCで導入の議論を経て仕様が決められ組み込まれました。

&& 演算子

&&演算子は前のコマンド(左オペランド)の結果が正常終了であれば後続の処理(右オペランド)を実行します。

# 前のコマンドが正常終了であれば後続の処理が実行される
Write-Output "Hello" && Write-Output "World"

# 前のコマンドが異常終了(下記は Write-Outpt と不正なコマンドレット名)であれば後続の処理は実行されない
Write-Outpt "Hello" && Write-Output "World"

PowerShellでは直前のコマンドの実行結果を$?自動変数で取得できますので、この演算子は

Write-Output "Hello"
if ($?) {
    Write-Output "World"
}

と書くのと等価です。

|| 演算子

||演算子は&&とは逆に前のコマンド(左オペランド)の結果が正常終了でなければ後続の処理(右オペランド)を実行します。

# 前のコマンドが正常終了であれば後続の処理は実行されない
Write-Output "Hello" || Write-Output "World"

# 前のコマンドが異常終了(下記は Write-Outpt と不正なコマンドレット名)であれば後続の処理が実行される
Write-Outpt "Hello" || Write-Output "World"

$?変数を使った場合だと以下と等価になります。

Write-Output "Hello"
if (-not $?) {
    Write-Output "World"
}

他シェルとの違い

PowerShell以外のシェルは外部コマンドを使うのが"ふつう"でありコマンドの終了判定も比較的シンプル(終了コードが 0 or それ以外)ですが、PowerShellでは内部コマンドであるコマンドレットを使うのが"ふつう"なためコマンドの終了判定が少し厄介です。

||&&演算子は厳密には両辺にパイプライン文を取り、言語仕様としては以下の様になります。

<pipeline statement> && <pipeline statement>

<pipeline statement> || <pipeline statement>

このパイプライン文の中で実行されるものがコマンドレットやスクリプトブロックといった内部コマンドに相当するものであれば基本的には"エラー"が発生しないかWrite-Errorを呼ばなければ正常終了となり、外部コマンド(PowerShell内部的にはNativeCommandと呼ばれる)の場合はそのコマンドの終了コードが0であれば正常終了となります。

ここで一つ非常に厄介な例を出すと、PowerShellでは括弧()や部分式$()を使ってしまうと中の式を別途評価してしまうためエラーだったものが正常終了になることがあります。

# これは左オペランドのパイプライン文はエラーとなる
Write-Error "Error" && Write-Output 'Hello'

# ()で囲ってしまっているので左オペランドのパイプライン文は正常終了と扱われる
(Write-Error "Error") && Write-Output 'Hello'

また、先程は"エラー"と一言で表現しましたが、パイプライン中で発生しうるエラーについては終了するエラー(Terminating Errors)終了しないエラー(non-Terminating Errors)、例外の直接Throwと複数種類あり、それぞれで微妙に挙動が異なるため注意が必要です。

具体的な違いについてはRFCのPipelinesの節をご覧ください。

注意事項

現時点では||&&演算子は試験的な機能として導入されています。
プレビュー版のPowerShellでは既定で試験的な機能が利用可能となっているためただちにこれらの演算子を利用できますが、試験的な機能を明示して無効にしている場合は以下のコマンドで機能を有効にしてください。

# Scopeは環境に応じて変えてください
Enable-ExperimentalFeature -Name PSPipelineChainOperators -Scope CurrentUser