146 votes

Coalescence des nuls dans powershell

Existe-t-il un opérateur de coalescence nul dans powershell ?

J'aimerais pouvoir faire ces commandes c# dans powershell :

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

194voto

StephenD Points 875

Powershell 7+

Powershell 7 introduit coalescence native des nuls, affectation conditionnelle des nuls et opérateurs ternaires dans Powershell.

Nulle Coalescence

$null ?? 100    # Result is 100

"Evaluated" ?? (Expensive-Operation "Not Evaluated")    # Right side here is not evaluated

Affectation conditionnelle nulle

$x = $null
$x ??= 100    # $x is now 100
$x ??= 200    # $x remains 100

Opérateur ternaire

$true  ? "this value returned" : "this expression not evaluated"
$false ? "this expression not evaluated" : "this value returned"

Versions précédentes :

Pas besoin des extensions communautaires Powershell, vous pouvez utiliser les instructions standard Powershell if comme expression :

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

Donc aux remplacements pour votre première expression C# de :

var s = myval ?? "new value";

devient l'un des éléments suivants (en fonction des préférences) :

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

ou en fonction de ce que $myval pourrait contenir, vous pourriez utiliser :

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

et la seconde expression en C# se transforme de manière similaire :

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

devient

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

Pour être honnête, ces formulaires ne sont pas très rapides et sont loin d'être aussi confortables à utiliser que les formulaires C#.

Vous pouvez également envisager de l'envelopper dans une fonction très simple pour rendre les choses plus lisibles :

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

$s = Coalesce $myval "new value"

ou éventuellement comme, IfNull :

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

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

Comme vous pouvez le constater, une fonction très simple peut vous donner une grande liberté de syntaxe.

MISE À JOUR : Une option supplémentaire à considérer dans le mélange est une fonction IsTrue plus générique :

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

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

Si l'on combine cela avec la capacité de Powershell à déclarer des alias qui ressemblent un peu à des opérateurs, on obtient.. :

New-Alias "??" Coalesce

$s = ?? $myval "new value"

New-Alias "?:" IfTrue

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

Il est évident que cela ne sera pas du goût de tout le monde, mais cela peut correspondre à ce que vous recherchez.

Comme le note Thomas, une autre différence subtile entre la version C# et la précédente est que C# effectue un court-circuitage des arguments, mais les versions Powershell impliquant des fonctions/aliases évalueront toujours tous les arguments. Si cela pose un problème, utilisez l'option if forme d'expression.

7 votes

Le seul véritable équivalent de l'opérateur de coalescence est l'utilisation d'une instruction if ; le problème est que toute autre approche évalue tous les opérandes au lieu de les court-circuiter. L'expression " ?? $myval SomeReallyExpenisveFunction()" appellera la fonction même si $myval n'est pas nul. Je suppose que l'on pourrait retarder l'évaluation en utilisant des blocs de script, mais il faut savoir que les blocs de script ne sont PAS des fermetures, et que les choses commencent à devenir compliquées.

0 votes

Ne fonctionne pas en mode strict -- il lance The variable '$myval' cannot be retrieved because it has not been set. .

1 votes

@BrainSlugs83 L'erreur que vous rencontrez en mode strict n'est pas liée aux options de coalescence des nullités présentées. Il s'agit simplement du contrôle standard de Powershell qui vérifie qu'une variable est définie en premier. Si vous définissez $myval = $null avant d'effectuer le test, l'erreur devrait disparaître.

101voto

Zenexer Points 4192

PowerShell 7 et plus

PowerShell 7 introduit de nombreuses nouvelles fonctionnalités et migre de .NET Framework vers .NET Core. À la mi-2020, il n'a pas encore complètement remplacé les anciennes versions de PowerShell en raison de la dépendance à l'égard de .NET Core, mais Microsoft a indiqué que la famille Core avait l'intention de remplacer à terme la famille Framework. Au moment où vous lirez ces lignes, une version compatible de PowerShell sera peut-être préinstallée sur votre système. https://github.com/powershell/powershell .

Par la documentation Les opérateurs suivants sont pris en charge dès le départ dans PowerShell 7.0 :

  1. Coalescence nulle : ??
  2. Assignation sans coalescence : ??=
  3. Ternaire : ... ? ... : ...

Ils fonctionnent comme on peut s'y attendre pour une coalescence nulle :

$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'

Depuis qu'un opérateur ternaire a été introduit, ce qui suit est maintenant possible, bien que cela soit inutile étant donné l'ajout d'un opérateur de coalescence nul :

$x = $a -eq $null ? $b : $a

À partir de la version 7.0, les éléments suivants sont également disponibles si l'option PSNullConditionalOperators La fonction optionnelle est activé comme expliqué dans la documentation ( 1 , 2 ) :

  1. Accès aux membres sans condition pour les membres : ?.
  2. Accès aux membres sans condition pour les tableaux et autres : ?[]

Celles-ci comportent quelques mises en garde :

  1. Étant donné qu'il s'agit d'expériences, elles sont susceptibles d'être modifiées. Il se peut qu'ils ne soient plus considérés comme expérimentaux au moment où vous lirez ces lignes, et la liste des avertissements peut avoir changé.
  2. Les variables doivent être entourées de ${} s'il est suivi par l'un des opérateurs expérimentaux, car les points d'interrogation sont autorisés dans les noms de variables. Il n'est pas clair si cela sera le cas si/quand les fonctionnalités passeront du statut expérimental (cf. numéro 11379 ). Par exemple, ${x}?.Test() utilise le nouvel opérateur, mais $x?.Test() exécute Test() sur une variable nommée $x? .
  3. Il n'y a pas ?( comme vous pouvez vous y attendre si vous venez de TypeScript. Ce qui suit ne fonctionnera pas : $x.Test?()

PowerShell 6 et antérieurs

Les versions de PowerShell antérieures à 7 disposent d'un opérateur de coalescence des nullités, ou du moins d'un opérateur capable d'un tel comportement. Cet opérateur est -ne :

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

# Output:
alpha

Il est un peu plus polyvalent qu'un opérateur de coalescence des éléments nuls, puisqu'il crée un tableau de tous les éléments non nuls :

$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 fonctionne de manière similaire, ce qui est utile pour compter les entrées nulles :

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

# Result:
2

Quoi qu'il en soit, voici un cas typique qui reflète celui du C#. ?? opérateur :

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

Explication

Cette explication est basée sur une suggestion d'édition d'un utilisateur anonyme. Merci, qui que vous soyez !

En se basant sur l'ordre des opérations, cela fonctionne dans l'ordre suivant :

  1. En , L'opérateur crée un tableau de valeurs à tester.
  2. En -ne filtre tous les éléments du tableau qui correspondent à la valeur spécifiée - dans ce cas, null. Le résultat est un tableau de valeurs non nulles dans le même ordre que le tableau créé à l'étape 1.
  3. [0] est utilisé pour sélectionner le premier élément du tableau filtré.

Simplifier cela :

  1. Créez un tableau de valeurs possibles, dans l'ordre souhaité
  2. Exclure toutes les valeurs nulles du tableau
  3. Prenez le premier élément du tableau résultant

Avertissements

Contrairement à l'opérateur null coalescing du C#, toutes les expressions possibles seront évaluées, puisque la première étape consiste à créer un tableau.

0 votes

J'ai fini par utiliser une version modifiée de votre réponse dans la mienne car j'avais besoin de permettre à toutes les instances de la coalescence d'être nulles, sans lever d'exception. Mais c'est une très bonne façon de faire, qui m'a beaucoup appris :)

0 votes

Cette méthode permet d'éviter les courts-circuits. Définir function DidItRun($a) { Write-Host "It ran with $a"; return $a } et exécuter ((DidItRun $null), (DidItRun 'alpha'), 1 -ne $null)[0] pour voir ceci.

0 votes

@jpmc26 Oui, c'est voulu.

15voto

Duncan Points 25356

Ce n'est qu'une demi réponse à la première moitié de la question, donc un quart de réponse si vous voulez, mais il existe une alternative beaucoup plus simple à l'opérateur de coalescence nul, à condition que la valeur par défaut que vous voulez utiliser soit effectivement la valeur par défaut du type :

string s = myval ?? "";

Peut être écrit en Powershell comme :

([string]myval)

Ou

int d = myval ?? 0;

traduit en Powershell :

([int]myval)

J'ai trouvé la première utile lors du traitement d'un élément xml qui pourrait ne pas exister et qui, s'il existait, pourrait avoir un espace blanc indésirable autour de lui :

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

Le passage à une chaîne de caractères protège l'élément contre la nullité et évite tout risque de conflit entre les deux éléments. Trim() à défaut.

0 votes

([string]$null) -> "" semble être un "effet secondaire utile, mais malheureux" :(

14voto

Chris F Carroll Points 724

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

renvoie à

3

1 votes

Mais le commentaire de @thomas-s-trias sur les courts-circuits est toujours valable.

9voto

EBGreen Points 14478

Si vous installez le Module d'extension de la communauté Powershell alors vous pouvez utiliser :

? ?? est l'alias de Invoke-NullCoalescing.

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

? : est l'alias de Invoke-Ternary.

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

0 votes

En fait, ce ne sont pas des commandes PowerShell. Vous les avez eu ensemble avec pscx : ? : -> Invoke-Ternary

0 votes

... a manqué le code réel et le résultat.. ;) Get-Command -Module pscx -CommandType alias | where { $_.Name -match '\ ?.' } | foreach { "{0} : {1}" -f $_.Name, $_.Definition } ? : : Invoke-Ternary ?? : : Invoke-NullCoalescing

0 votes

Oups... vous avez tout à fait raison. J'oublie souvent que j'ai même ce module en charge.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X