PowerShellの戻り値の癖が強い

PowerShellのコードを書き始めたときに躓きやすいポイントについて

・関数の戻り値を複数返せる
最初にはまりそうな点。評価した値は全て戻り値として返る。
その点を理解していないと、戻り値を変数へ入れると想定と異なる値が返ることがあってはまる。
以下のような関数を書くとどうなるか。

function abc
{
  1     # 整数
  "abc" # 文字列
  0.123 # 浮動小数点数
}

上記の実行結果は以下のようになります。配列として値が全部返ります(・ω・)
PowerShellは関数型言語ですが、値を一個だけではなく、複数返せるようになっているのがLispなどとは異なる点。
※Lispでは最後に評価した値のみ返ります。
戻り値は型の混在もOK(*'▽')

PS > abc
1
"abc"
0.123
PS > $a = abc
PS > $a
1
"abc"
0.123
PS > $a.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

上記のように評価した値は全て返るようになっています。
複数の値を変数へ代入するとデータ型は配列(System.Array)となります。
複数の値を別の型でも返せるので、意図して複数の値を返す場合は便利ですが、バグの原因にもなるので注意が必要。

# 不具合例
function bug_by2($num)
{
  # 先ほど定義した関数。関数を評価しても値が返ります。
  abc
  $num * 2 # 本当に返したい値
}
# 実行する
PS> bug_by2 2
1
"abc"
0.123
4
# ↑意図せずたくさん値が帰ってしまう...

function num_by2($num)
{
  # 値を返す関数を使うが、戻り値を使いたくない場合はこうします。
  $a = abc # 変数で受ける。
  abc | Out-Null # パイプで値を捨てる。
  $num * 2 # 本当に返したい値
}

PS> num_by2 2
4# 意図した値のみ返った(*'▽')

上記のように、戻り値を使いたくない場合は値を変数で受けるか、捨てる必要があります。実際の例。

# 実際のコード例はこちら
function Start-ProcessByName($Name)
{
  try{
    # プロセス情報を取得。値は要らないので捨てる。
    Get-Process -Name $Name | Out-Null
    Write-Host "Already launched"
    return
  }
  catch{
    # 起動していない場合は例外が発生
  }
  Start-Process -FilePath ($Name + ".exe")
}
 #実行例 
PS > Start-ProcessByName notepad
PS > Start-ProcessByName notepad
Already launched

上記はGet-Processで二重起動チェックを行い、起動していない場合にプロセス起動する関数です。
Get-Processでは起動の有無だけ知りたいので値は捨てています。

戻り値の返し方や関数の定義の仕方を見ると、Powershellはシェルスクリプトですが、関数言語としての性格が非常に強い言語だと思います。
JavaScriptやLispと同系統の言語と思った方がいいと思います。
C++とかJAVAといった言語とは性格が随分異なります。

この記事が気に入ったらサポートをしてみませんか?