¿Por qué Powershell convierte silenciosamente una matriz de cadenas con un elemento en una cadena?

33

Considere el siguiente script de Powershell, que busca carpetas en C: \ con un 'og' en su nombre:

PS C: \> (ls |% {$ _. Name} |? {$ _. Contiene ("og")})
PerfLogs
Archivos de programa
setup.log

Ahora limito la búsqueda para obtener solo un elemento:

PS C: \> (ls |% {$ _. Name} |? {$ _. Contiene ("Prog")})
Archivos de programa

Lo extraño es que la primera operación produce una matriz , mientras que la segunda operación (que en mi humilde opinión es semánticamente la misma operación, por lo que debería producir el mismo tipo de resultado) produce una cadena . Esto se puede ver en el siguiente resultado:

PS C: \> (ls |% {$ _. Name} |? {$ _. Contiene ("og")}). Longitud
3
PS C: \> (ls |% {$ _. Name} |? {$ _. Contiene ("Prog")}). Longitud
13

Esto puede ser muy irritante, ya que aparentemente hay menos carpetas que coinciden con 'og' que las que coinciden con 'Prog'.

Evidentemente, PowerShell 'desempaqueta' implícitamente una matriz de un solo elemento en un solo objeto, y nunca obtenemos una matriz de longitud 1. Parece que cada vez que quiero contar los resultados que vienen por la tubería, tengo que verificar si ' Estoy tratando con una matriz o no.

¿Cómo puedo evitar que esto suceda? Como tratas con esto?

cheesus así que deja de dañar a Monica
fuente
Estos de StackOverflow pueden ayudar: stackoverflow.com/questions/1827862/… stackoverflow.com/questions/1390782/… Si no estaba conectado $_.Contains, entonces %{,,$_.Name}funciona ...
Bob

Respuestas:

56

Evidentemente, PowerShell 'desempaqueta' implícitamente una matriz de un solo elemento en un solo objeto,

Y cero resultados del artículo a $null.

¿Cómo puedo evitar que esto suceda?

No puedes

Como tratas con esto?

Utilice el constructor de matrices ( @(...)) para forzar el retorno de una colección (posiblemente con cero o un elemento):

$res = @(ls | %{$_.Name} | ?{$_.Contains("Prog")})
Ricardo
fuente
Gracias, esto es perfecto! Votaré en cuanto tenga 15 reputación.
Cheesus así que deja de dañar a Mónica
2
No estoy seguro de que pueda "forzarlo". @(1) | ConvertTo-JsonTodavía regresa en 1lugar de [1].
Marc
@Marc: ConvertTo-Jsonnunca devuelve una colección: lee toda la entrada y la convierte en una sola cadena. Si desea convertir objetos de entrada individualmente, deberá procesar cada uno por separado.
Richard
1
@ Richard, creo que malinterpretas: yo, y muchos otros, básicamente queremos que se serialice todo el objeto (es decir, la colección) (por ejemplo, por persistencia externa). No estamos interesados ​​en procesar cada objeto de la colección por separado. ConvertTo-Json debería devolver una cadena que, si se ejecuta, ConvertFrom-Json devuelve el objeto original aunque sea una matriz / colección vacía.
Marc
@Marc El objetivo de esta pregunta es evitar el tratamiento de una matriz de un solo elemento como ese elemento (que es un problema menor debido a los cambios posteriores de PSH: tenga en cuenta la fecha de la pregunta). Estás hablando de un caso completamente diferente (obligando a una colección a ser un solo objeto), por lo tanto, no entiendo bien.
Richard
2

Esto se ha resuelto en PowerShell v3:

http://blogs.microsoft.co.il/blogs/scriptfanatic/archive/2012/03/19/Counting-objects-in-PowerShell-3.0.aspx

En una nota al margen, puede encontrar si un nombre contiene algo usando un comodín:

PS> ls *og*
Shay Levy
fuente
66
Shay , todavía no puedo comentar las respuestas, pero tu afirmación no es cierta. PowerShell todavía contiene elementos en cajas, pero, como ha notado, han dado a los elementos individuales un valor de "Recuento". Sin embargo, los resultados de elementos individuales aún no están empaquetados. Puede probar el ejemplo anterior con PS 3 y ver los resultados.
Tohuw
1
El comportamiento sigue siendo el mismo en PS 5.
MEMark
Sí, def todavía presente
James Wiseman
1
Este comportamiento sigue siendo el mismo en PS 6.0.1
spuder
2

Tenga en cuenta la diferencia entre estos dos resultados:

PS C:\> ConvertTo-Json -InputObject @(1)
[
    1
]
PS C:\> @(1)|ConvertTo-Json
1
PS C:\>

El punto es que la operación de tubería está haciendo el 'desempaquetado'. ConvertTo-Json todavía ve el objeto como una matriz si usamos InputObject en lugar de tuberías.

Larry Young
fuente