windows powershell file compare member-enumeration

windows - Powershell: archivo nulo siempre generado(salida de Comparar-Objeto)



file compare (2)

Quizás en vez de

$LeftSide = ($Diff | Where-Object {$_.SideIndicator -eq ''<=''}).InputObject

PowerShell 2 podría funcionar mejor con:

$LeftSide = $Diff | Where-Object {$_.SideIndicator -eq ''<=''} | Foreach-object { $_.InputObject }

La respuesta más popular para esta pregunta implica el siguiente código de Windows PowerShell (editado para corregir un error):

$file1 = Get-Content C:/temp/file1.txt $file2 = Get-Content C:/temp/file2.txt $Diff = Compare-Object $File1 $File2 $LeftSide = ($Diff | Where-Object {$_.SideIndicator -eq ''<=''}).InputObject $LeftSide | Set-Content C:/temp/file3.txt

Siempre obtengo un archivo de cero bytes como salida, incluso si elimino la línea $ Diff.

¿Por qué el archivo de salida siempre es nulo y cómo se puede solucionar?


PetSerAl , como lo hace habitualmente, ha proporcionado el puntero crucial en un comentario sobre la pregunta (sin la intención de convertirla en una respuesta):

Enumeración de miembros : la capacidad de acceder a un miembro (una propiedad o un método) en una colección y aplicarla implícitamente a cada uno de sus elementos , con los resultados recogidos en una matriz , se introdujo en PSv3 .

La enumeración de miembros no solo es expresiva y conveniente , sino que también es más rápida que los enfoques alternativos .

Un ejemplo simplificado:

PS> ((Get-Item /), (Get-Item $HOME)).Mode d--hs- # The value of (Get-Item /).Mode d----- # The value of (Get-Item $HOME).Mode

La aplicación de .Mode a la colección que genera el comando (...) cerrado hace que se .Mode propiedad .Mode en cada elemento de la colección , con los valores resultantes devueltos como una matriz (una matriz PowerShell normal, de tipo [System.Object[]] ).

Advertencias : la enumeración de miembros maneja la matriz resultante como lo hace la canalización , lo que significa:

  • Si la matriz tiene un solo elemento, el valor de la propiedad de ese elemento se devuelve directamente , no dentro de una matriz de un solo elemento:

    PS> @([pscustomobject] @{foo=1}).foo.GetType().Name Int32 # 1 was returned as a scalar, not as a single-element array.

  • Si los valores de propiedad que se recopilan son en sí mismos matrices, se devuelve una matriz plana de valores:

    PS> @([pscustomobject] @{foo=1,2}, [pscustomobject] @{foo=3,4}).foo.Count 4 # a single, flat array was returned: 1, 2, 3, 4

Además, la enumeración de miembros solo funciona para obtener (leer) valores de propiedad , no para establecerlos (escribirlos). Esta asimetría es por diseño , para evitar modificaciones masivas potencialmente no deseadas; en PSv4 +, use .ForEach(''<property-name'', <new-value>) como la solución más rápida (ver más abajo).

Sin embargo, esta práctica característica NO está disponible :

  • si estás ejecutando en PSv2 (categóricamente)
  • si la colección en sí tiene un miembro con el nombre especificado , en cuyo caso se aplica el miembro de nivel de colección.

Por ejemplo, incluso en PSv3 + lo siguiente NO realiza la enumeración de miembros:

PS> (''abc'', ''cdefg'').Length # Try to report the string lengths 2 # !! The *array''s* .Length property value (item count) is reported, not the items''

En tales casos, y en PSv2 en general, se necesita un enfoque diferente:

  • Alternativa más rápida , utilizando la instrucción foreach , suponiendo que toda la colección se ajusta a la memoria como un todo (lo que está implícito cuando se usa la enumeración de miembros).

PS> foreach ($s in ''abc'', ''cdefg'') { $s.Length } 3 5

  • Alternativa PSv4 + , utilizando el método de recopilación .ForEach() , que también opera en la recopilación en su conjunto:

PS> (''abc'', ''cdefg'').ForEach(''Length'') 3 5

Nota: Si corresponde a la colección de entrada, también puede establecer valores de propiedad con .ForEach(''<prop-name>'', <new-value>) , que es la solución más rápida para no poder usar .<prop-name> = <new-value> , es decir, la incapacidad de establecer valores de propiedad con la enumeración de miembros.

  • Enfoques más lentos, pero eficientes en memoria , utilizando la canalización :

Nota: El uso de la canalización solo es eficiente en la memoria si procesa los elementos uno por uno, de forma aislada, sin recopilar los resultados en la memoria también.

Usando el cmdlet ForEach-Object , como en la útil respuesta de Burt Harris :

PS> ''abc'', ''cdefg'' | ForEach-Object { $_.Length } 3 5

Solo para propiedades (a diferencia de los métodos), Select-Object -ExpandProperty es una opción; es conceptualmente claro y simple, y prácticamente a la par con el enfoque ForEach-Object en términos de rendimiento (para una comparación de rendimiento, consulte la última sección de esta respuesta mía):

PS> ''abc'', ''cdefg'' | Select-Object -ExpandProperty Length 3 5