58 votes

Pourquoi Powershell convertit-il silencieusement un tableau de chaînes de caractères avec un seul élément en une chaîne de caractères ?

Prenons l'exemple du Powershell script suivant, qui recherche dans C:\ les dossiers dont le nom contient un "og" :

PS C:\\> (ls | %{$\_.Name} | ?{$\_.Contains("og")})
PerfLogs
Program Files
setup.log

Maintenant, je restreins la recherche pour n'obtenir qu'un seul élément :

PS C:\\> (ls | %{$\_.Name} | ?{$\_.Contains("Prog")})
Program Files

Ce qui est étrange, c'est que la première opération donne un réseau alors que la seconde opération (qui est sémantiquement la même opération, et qui devrait donc donner le même type de résultat) donne un chaîne de caractères . Cela se traduit par le résultat suivant :

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

Cela peut être très irritant, car il y a apparemment moins de dossiers qui correspondent à "og" que de dossiers qui correspondent à "Prog".

Manifestement, PowerShell "décompose" implicitement un tableau d'un seul élément en un seul objet, et nous n'obtenons jamais un tableau de longueur 1. Il semble que chaque fois que je veux compter les résultats qui arrivent dans le pipeline, je dois vérifier si j'ai affaire à un tableau ou non.

Comment éviter que cela ne se produise ? Comment faites-vous face à ce problème ?

76voto

codemac Points 689

De toute évidence, PowerShell "décompresse" implicitement un tableau à un seul élément en un seul objet,

Et zero item results to $null .

Comment puis-je éviter que cela ne se produise ?

Vous ne pouvez pas.

Comment gérez-vous cette situation ?

Utilisez le constructeur de tableau ( @(...) ) pour forcer le retour d'une collection (éventuellement avec zéro ou un seul élément) :

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

15voto

Larry Young Points 141

Notez la différence entre ces deux résultats :

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

L'intérêt est que la "désimbrication" est effectuée par l'opération du tuyau. ConvertTo-Json voit toujours l'objet comme un tableau si nous utilisons InputObject plutôt que le pipe.

3voto

Ranjan Dahal Points 21

Une alternative à ce problème consiste à définir explicitement le type de la variable comme étant un tableau :

[array]$res = (ls | %{$_.Name} | ?{$_.Contains("og")})

1voto

Ed. Points 1089

Ce problème a été résolu dans PowerShell v3 :

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

Par ailleurs, vous pouvez déterminer si un nom contient quelque chose en utilisant un caractère de remplacement :

PS> ls *og*

1voto

John Davis Points 11

Cela a fonctionné pour moi, mais j'ai dû déclarer les résultats dans une nouvelle variable, ou PowerShell a continué à décomposer le tableau en un seul objet... c'est très frustrant.

Merci à Microsoft de ne pas avoir pris en compte les cas d'utilisation de JSON... insérer un sarcasme virulent

$result = ConvertTo-Json -InputObject @($body) -compress

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X