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