Perché Powershell converte silenziosamente un array di stringhe con un elemento in una stringa


33

Considera il seguente script Powershell, che cerca le cartelle in C: \ con un 'og' nel loro nome:

PS C: \> (ls |% {$ _. Nome} |? {$ _. Contiene ("og")})
PerfLogs
File di programma
Setup.log

Ora restringo la ricerca per ottenere un solo elemento:

PS C: \> (ls |% {$ _. Nome} |? {$ _. Contiene ("Prog")})
File di programma

La cosa strana è che la prima operazione produce un array , mentre la seconda operazione (che è IMHO semanticamente la stessa operazione, quindi dovrebbe produrre lo stesso tipo di risultato) produce una stringa . Questo può essere visto nel seguente risultato:

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

Questo può essere molto irritante, poiché apparentemente ci sono meno cartelle che corrispondono a "og" rispetto a quelle che corrispondono a "Prog".

Evidentemente, PowerShell "decomprime" implicitamente un array a singolo elemento in un singolo oggetto e non otteniamo mai un array di lunghezza 1. Sembra che ogni volta che voglio contare i risultati che arrivano sulla pipeline, devo verificare se ho a che fare con un array o no.

Come posso evitare che ciò accada? come lo gestisci?


Questi da StackOverflow possono essere d'aiuto: stackoverflow.com/questions/1827862/… stackoverflow.com/questions/1390782/… Se non stavi eseguendo il piping $_.Contains, allora %{,,$_.Name}funziona ...
Bob

Risposte:


56

Evidentemente, PowerShell "decomprime" implicitamente un array a singolo elemento in un singolo oggetto,

E zero risultati dell'oggetto a $null.

Come posso evitare che ciò accada?

Non puoi.

come lo gestisci?

Utilizzare il costruttore di array ( @(...)) per forzare una raccolta (possibilmente con zero o un elemento) return:

$res = @(ls | %{$_.Name} | ?{$_.Contains("Prog")})

Grazie, è perfetto! Valuterò non appena avrò 15 reputazione.
Cheesus SO smette di fare del male a Monica il

2
Non sono sicuro di poterlo "forzare". @(1) | ConvertTo-Jsonrestituisce comunque 1invece di [1].
Marc,

@Marc: ConvertTo-Jsonnon restituisce mai una raccolta: legge l'intero input e si converte in una singola stringa. Se desideri che gli oggetti di input vengano convertiti individualmente, dovrai elaborarli separatamente.
Richard,

1
@Richard, penso che tu abbia frainteso: io, e molti altri, fondamentalmente voglio l'intero oggetto (cioè la raccolta) serializzato (ad esempio per la persistenza esterna). Non siamo interessati a elaborare ogni oggetto nella raccolta separatamente. ConvertTo-Json dovrebbe restituire una stringa che, se eseguita, ConvertFrom-Json restituisce l'oggetto originale sebbene in una matrice / raccolta vuota.
Marc,

@Marc Il punto di questa domanda è evitare il trattamento di un singolo array di elementi come quell'elemento (che è meno un problema a causa delle successive modifiche del PSH: annotare la data della domanda). Stai parlando di un caso completamente diverso (forzando una collezione ad essere un singolo oggetto), quindi mi fraintendo.
Richard,

2

Questo è stato risolto in PowerShell v3:

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

In una nota a margine, puoi trovare se un nome contiene qualcosa usando un carattere jolly:

PS> ls *og*

6
Shay , non posso ancora commentare le risposte, ma la tua affermazione non è vera. PowerShell inscatola ancora elementi, ma hanno, come hai notato, assegnato ai singoli elementi un valore "Conteggio". Tuttavia, i risultati di un singolo articolo non sono ancora stati riordinati. Puoi testare l'esempio sopra su PS 3 e vedere i risultati.
Tohuw,

1
Il comportamento è sempre lo stesso in PS 5.
MEMark

Sì, def ancora presente
James Wiseman,

1
Questo comportamento è sempre lo stesso in PS 6.0.1
spuder

2

Nota la differenza tra questi due risultati:

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

Il punto è che il 'unboxing' viene eseguito dall'operazione pipe. ConvertTo-Json vede ancora l'oggetto come un array se utilizziamo InputObject anziché piping.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.