Fusión nula en powershell


¿Hay un operador coalescente nulo en powershell?

Me gustaría poder hacer estos comandos de c# en powershell:

var s = myval ?? "new value";
var x = myval == null ? "" : otherval;
Author: Micah, 2012-05-16

8 answers

No es necesario usar las extensiones de la comunidad de Powershell, puede usar las instrucciones if estándar de Powershell como expresión:

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

Así que para los reemplazos de su primera expresión es:

var s = myval ?? "new value";

Se convierte en uno de los siguientes (dependiendo de la preferencia):

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

O dependiendo de lo que contain myval podría contener, podría usar:

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

Y la segunda expresión se mapea de manera similar:

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

Se convierte en

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

Ahora, para ser justos, estos no son muy ágil, y no es tan cómodo de usar como los formularios C#.

También podría considerar envolverlo en una función muy simple para hacer las cosas más legibles:

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

$s = Coalesce $myval "new value"

O posiblemente como, IfNull:

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

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

Como puede ver, una función muy simple puede darle bastante libertad de sintaxis.

ACTUALIZACIÓN: Una opción adicional a considerar en la mezcla es una función genericue más genérica:

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

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

A continuación, combine que es la capacidad de Powershell para declarar los alias que se parecen un poco a los operadores, terminan con:

New-Alias "??" Coalesce

$s = ?? $myval "new value"

New-Alias "?:" IfTrue

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

Claramente esto no va a ser del gusto de todos, pero puede ser lo que estás buscando.

 91
Author: StephenD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-17 19:59:14

Sí, PowerShell tiene un operador coalescente null real, o al menos un operador que es capaz de tal comportamiento. Ese operador es -ne:

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

# Output:
alpha

Es un poco más versátil que un operador coalescente nulo, ya que crea una matriz de todos los elementos no nulos:

$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 funciona de manera similar, lo cual es útil para contar entradas nulas:

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

# Result:
2

Pero de todos modos, aquí hay un caso típico para reflejar C # ' s ?? operador:

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

Explicación

Esta explicación se basa en una sugerencia de edición de un usuario anónimo. ¡Gracias, quienquiera que seas!

Basado en el orden de operaciones, esto funciona en el siguiente orden:

  1. El operador , crea una matriz de valores a probar.
  2. El operador -ne filtra cualquier elemento de la matriz que coincida con el valor especificado--en este caso, null. El resultado es una matriz de valores no nulos en el mismo ordenar como la matriz creada en el paso 1.
  3. [0] se utiliza para seleccionar el primer elemento de la matriz filtrada.

Simplificando eso:

  1. Crear una matriz de valores posibles, en orden preferido
  2. Excluir todos los valores nulos de la matriz
  3. Tome el primer elemento de la matriz resultante

Advertencias

A diferencia del operador coalescente null de C#, cada expresión posible será evaluada, ya que el primer paso es crear un matriz.

 65
Author: Zenexer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-06 05:04:16

Esto es solo la mitad de una respuesta a la primera mitad de la pregunta, por lo que una cuarta respuesta si se quiere, pero hay una alternativa mucho más simple al operador de coalescencia null siempre que el valor predeterminado que desea usar sea en realidad el valor predeterminado para el tipo:

string s = myval ?? "";

Se puede escribir en Powershell como:

([string]myval)

O

int d = myval ?? 0;

Se traduce a Powershell:

([int]myval)

Encontré el primero de estos útiles al procesar un elemento xml que podría no existir y que si existió podría tener espacios en blanco no deseados alrededor de él:

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

El cast to string protege contra que el elemento sea nulo y evita cualquier riesgo de que Trim() falle.

 11
Author: Duncan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-03 10:50:03

Si instala el Módulo Powershell Community Extensions entonces puede usar:

?? es el alias de Invoke-NullCoalescing.

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

?: es el alias de Invoke-Ternary.

$x = ?: {$myval -eq $null} {""} {$otherval}
 8
Author: EBGreen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-16 19:24:43

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

Devuelve

3

 4
Author: Chris F Carroll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-21 13:31:42
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
Author: Shawn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-29 00:05:20

A menudo encuentro que también necesito tratar la cadena vacía como null cuando uso coalesce. Terminé escribiendo una función para esto, que usa la solución de Zenexer para coalescer para la coalescencia null simple, y luego usé Keith Hill para verificar null o empty, y agregué eso como una bandera para que mi función pudiera hacer ambas cosas.

Una de las ventajas de esta función es que también maneja tener todos los elementos nulos (o vacíos), sin lanzar una excepción. También se puede utilizar para muchas variables de entrada arbitrarias, gracias a cómo PowerShell maneja las entradas de matriz.

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)
  }  
}

Esto produce los siguientes resultados de la prueba:

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

Código de prueba:

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)
 1
Author: Johny Skovdal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:54

Lo más cercano que puedo conseguir es: $s = $myval |?? "new value"

Implementé el operador de coalescencia null para lo anterior de la siguiente manera:

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

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

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

El operador ternario condicional podría implementarse de manera similar.

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

Y se usa como: $x = ($myval -eq $null) |?: "" $otherval

 0
Author: Elon Mallin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-07 08:59:16