いわゆる early-return というものを PowerShell でやろうとしたときにハマったのでメモ。
環境
Name Value
---- -----
PSVersion 7.0.3
PSEdition Core
GitCommitId 7.0.3
OS Microsoft Windows 10.0.18362
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
経緯
PowerShell では見出しが重複した csv を ConvertFrom-Csv
しようとするとエラーが出ます。
PS> cat .\target.csv
AA,AA,BB
10,20,30
40,50,60
PS> cat target.csv | ConvertFrom-Csv
ConvertFrom-Csv: The member "AA" is already present.
しかし次の関数を実行してみると……
function func1 {
if($true){
return (cat target.csv | ConvertFrom-Csv)
}
Write-Output "ここは出力されてほしくない"
}
どうも return に失敗すると return 処理が無視されて 以降の行に処理が移っている様子。-ErrorAction
パラメータに Stop
を指定しても関係ないようです。
function func2 {
if($true){
return (cat target.csv | ConvertFrom-Csv -ErrorAction Stop)
}
Write-Output "ここは出力されてほしくない"
}
明示的に Write-Output
するとその行でエラーとして処理が止まるようです。しかし記述を簡略化するための early-return で文字数が増えるのは本末転倒……
function func3 {
if($true){
cat target.csv | ConvertFrom-Csv | Write-Output
return
}
Write-Output "ここは出力されてほしくない"
}
変数に格納するようにしたらちゃんとエラー扱いになりました。少し記述が減ります。
function func4 {
if($true){
$ret = (cat target.csv | ConvertFrom-Csv)
return $ret
}
Write-Output "ここは出力されてほしくない"
}
変数に格納すればよいことがわかったので、 return $()
とするのが最も簡単ですね。
function func5 {
if($true){
return $(cat target.csv | ConvertFrom-Csv)
}
Write-Output "ここは出力されてほしくない"
}
結局、$
1つ加えるだけで良かったのでした(しかし Qiita のシンタックスハイライト的にはエラー…?)。
結論
return 内容は変数に格納するべし。
return 処理自体がなかったことになるのは結構な罠ですね。ドキュメント にも ()
はその中をすべて評価してから以降にパイプするという以上の説明がないので慌てました。心臓に悪い……。