web-dev-qa-db-ja.com

PowershellでのNull合体

PowerShellにヌル合体演算子がありますか?

私はpowershellでこれらのc#コマンドを実行できるようにしたいと思います:

var s = myval ?? "new value";
var x = myval == null ? "" : otherval;
92
Micah

Powershell Community Extensionsは必要ありません。標準のPowershell ifステートメントを式として使用できます。

variable = if (condition) { expr1 } else { expr2 }

したがって、最初のC#式の置換:

var s = myval ?? "new value";

次のいずれかになります(設定によります)。

$s = if ($myval -eq $null) { "new value" } else { $myval }
$s = if ($myval -ne $null) { $myval } else { "new value" }

または、$ myvalの内容に応じて使用できます:

$s = if ($myval) { $myval } else { "new value" }

そして、2番目のC#式は同様の方法でマップします。

var x = myval == null ? "" : otherval;

になる

$x = if ($myval -eq $null) { "" } else { $otherval }

公平を期すために、これらはそれほどきびきびしておらず、C#フォームほど使いやすいものではありません。

さらに読みやすくするために、非常に単純な関数でラップすることを検討することもできます。

function Coalesce($a, $b) { if ($a -ne $null) { $a } else { $b } }

$s = Coalesce $myval "new value"

または場合によっては、IfNull:

function IfNull($a, $b, $c) { if ($a -eq $null) { $b } else { $c } }

$s = IfNull $myval "new value" $myval
$x = IfNull $myval "" $otherval

ご覧のとおり、非常に単純な関数を使用すると、構文のかなりの自由度が得られます。

更新:ミックスで考慮する1つの追加オプションは、より一般的なIsTrue関数です。

function IfTrue($a, $b, $c) { if ($a) { $b } else { $c } }

$x = IfTrue ($myval -eq $null) "" $otherval

次に、演算子のように見えるエイリアスを宣言するPowershellの機能である結合すると、次のようになります。

New-Alias "??" Coalesce

$s = ?? $myval "new value"

New-Alias "?:" IfTrue

$ans = ?: ($q -eq "meaning of life") 42 $otherval

明らかにこれは誰の好みにもなりそうではありませんが、あなたが探しているものかもしれません。

Thomasが指摘しているように、C#バージョンと上記のもう1つの微妙な違いは、C#が引数の短絡を実行することですが、関数/エイリアスを含むPowershellバージョンは常にすべての引数を評価します。これが問題になる場合は、if式形式を使用してください。

108
StephenD

はい、PowerShellには実際のnull合体演算子、または少なくともこのような動作が可能な演算子があります。その演算子は-ne

# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]

# Output:
alpha

これは、すべての非ヌル項目の配列を作成するため、ヌル合体演算子よりも少し汎用性があります。

$items = $null, 'alpha', 5, 0, '', @(), $null, $true, $false
$instances = $items -ne $null
[string]::Join(', ', ($instances | ForEach-Object -Process { $_.GetType() }))

# Result:
System.String, System.Int32, System.Int32, System.String, System.Object[],
System.Boolean, System.Boolean

-eqも同様に機能し、nullエントリのカウントに役立ちます。

($null, 'a', $null -eq $null).Length

# Result:
2

しかし、とにかく、C#の??演算子:

'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output

説明

この説明は、匿名ユーザーからの編集提案に基づいています。ありがとうございました!

操作の順序に基づいて、これは次の順序で機能します。

  1. ,演算子は、テストする値の配列を作成します。
  2. -ne演算子は、指定された値(この場合はnull)に一致するすべての項目を配列から除外します。結果は、ステップ1で作成された配列と同じ順序の非NULL値の配列です。
  3. [0]は、フィルターされた配列の最初の要素を選択するために使用されます。

それを単純化する:

  1. 可能な値の配列を優先順に作成します
  2. 配列からすべてのヌル値を除外します
  3. 結果の配列から最初のアイテムを取得します

注意事項

C#のnull合体演算子とは異なり、最初のステップは配列を作成することなので、可能なすべての式が評価されます。

81
Zenexer

これは質問の前半に対する答えの半分にすぎないので、もしそうなら4分の1の答えですが、使用したいデフォルト値が実際にタイプのデフォルト値であるならば、null合体演算子のはるかに簡単な代替手段があります:

_string s = myval ?? "";
_

Powershellで次のように記述できます。

_([string]myval)
_

または

_int d = myval ?? 0;
_

powershellに変換します:

_([int]myval)
_

存在しないかもしれないXML要素を処理するときにこれらの最初のものが有用であることがわかりました。

_$name = ([string]$row.td[0]).Trim()
_

文字列へのキャストは、要素がnullになるのを防ぎ、Trim()が失敗するリスクを防ぎます。

13
Duncan

$null, $null, 3 | Select -First 1

返す

3

9
Chris F Carroll

Powershell Community Extensions Module をインストールすると、次を使用できます。

? Invoke-NullCoalescingのエイリアスです。

$s = ?? {$myval}  {"New Value"}

?:Invoke-Ternaryのエイリアスです。

$x = ?: {$myval -eq $null} {""} {$otherval}
9
EBGreen

合体を使用するときは、空の文字列をnullとして扱う必要があることもよくあります。単純なヌル合体の合体に Zenexer のソリューションを使用し、その後ヌルまたは空のチェックに Keith Hill を使用する関数を作成しました。それをフラグとして追加して、私の機能が両方を行えるようにしました。

この関数の利点の1つは、例外をスローせずにすべての要素をnull(または空)にすることも処理できることです。 PowerShellが配列入力を処理する方法のおかげで、任意の多くの入力変数にも使用できます。

function Coalesce([string[]] $StringsToLookThrough, [switch]$EmptyStringAsNull) {
  if ($EmptyStringAsNull.IsPresent) {
    return ($StringsToLookThrough | Where-Object { $_ } | Select-Object -first 1)
  } else {
    return (($StringsToLookThrough -ne $null) | Select-Object -first 1)
  }  
}

これにより、次のテスト結果が生成されます。

Null coallesce tests:
1 (w/o flag)  - empty/null/'end'                 : 
1 (with flag) - empty/null/'end'                 : end
2 (w/o flag)  - empty/null                       : 
2 (with flag) - empty/null                       : 
3 (w/o flag)  - empty/null/$false/'end'          : 
3 (with flag) - empty/null/$false/'end'          : False
4 (w/o flag)  - empty/null/"$false"/'end'        : 
4 (with flag) - empty/null/"$false"/'end'        : False
5 (w/o flag)  - empty/'false'/null/"$false"/'end': 
5 (with flag) - empty/'false'/null/"$false"/'end': false

テストコード:

Write-Host "Null coalesce tests:"
Write-Host "1 (w/o flag)  - empty/null/'end'                 :" (Coalesce '', $null, 'end')
Write-Host "1 (with flag) - empty/null/'end'                 :" (Coalesce '', $null, 'end' -EmptyStringAsNull)
Write-Host "2 (w/o flag)  - empty/null                       :" (Coalesce('', $null))
Write-Host "2 (with flag) - empty/null                       :" (Coalesce('', $null) -EmptyStringAsNull)
Write-Host "3 (w/o flag)  - empty/null/`$false/'end'          :" (Coalesce '', $null, $false, 'end')
Write-Host "3 (with flag) - empty/null/`$false/'end'          :" (Coalesce '', $null, $false, 'end' -EmptyStringAsNull)
Write-Host "4 (w/o flag)  - empty/null/`"`$false`"/'end'        :" (Coalesce '', $null, "$false", 'end')
Write-Host "4 (with flag) - empty/null/`"`$false`"/'end'        :" (Coalesce '', $null, "$false", 'end' -EmptyStringAsNull)
Write-Host "5 (w/o flag)  - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end')
Write-Host "5 (with flag) - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end' -EmptyStringAsNull)
2
Johny Skovdal
function coalesce {
   Param ([string[]]$list)
   #$default = $list[-1]
   $coalesced = ($list -ne $null)
   $coalesced[0]
 }
 function coalesce_empty { #COALESCE for empty_strings

   Param ([string[]]$list)
   #$default = $list[-1]
   $coalesced = (($list -ne $null) -ne '')[0]
   $coalesced[0]
 }
2
Shawn

私が得ることができる最も近い:$Val = $MyVal |?? "Default Value"

上記の null合体演算子 を次のように実装しました。

function NullCoalesc {
    param (
        [Parameter(ValueFromPipeline=$true)]$Value,
        [Parameter(Position=0)]$Default
    )

    if ($Value) { $Value } else { $Default }
}

Set-Alias -Name "??" -Value NullCoalesc

条件付き三項演算子 も同様の方法で実装できます。

function ConditionalTernary {
    param (
        [Parameter(ValueFromPipeline=$true)]$Value,
        [Parameter(Position=0)]$First,
        [Parameter(Position=1)]$Second
    )

    if ($Value) { $First } else { $Second }
}

Set-Alias -Name "?:" -Value ConditionalTernary

そして、次のように使用されます:$Val = $MyVal |?: $MyVal "Default Value"

0
Elon Mallin