120 votes

Boucler un hachage ou utiliser un tableau dans PowerShell

J'utilise ce morceau de code (simplifié) pour extraire un ensemble de tables du serveur SQL avec BCP .

$OutputDirectory = 'c:\junk\'
$ServerOption =   "-SServerName"
$TargetDatabase = "Content.dbo."

$ExtractTables = @(
    "Page"
    , "ChecklistItemCategory"
    , "ChecklistItem"
)

for ($i=0; $i -le $ExtractTables.Length – 1; $i++)  {
    $InputFullTableName = "$TargetDatabase$($ExtractTables[$i])"
    $OutputFullFileName = "$OutputDirectory$($ExtractTables[$i])"
    bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption
}

Cela fonctionne très bien, mais maintenant certaines tables doivent être extraites via des vues, et d'autres non. J'ai donc besoin d'une structure de données semblable à celle-ci :

"Page"                      "vExtractPage"
, "ChecklistItemCategory"   "ChecklistItemCategory"
, "ChecklistItem"           "vExtractChecklistItem"

Je me suis penché sur les hachages, mais je n'ai rien trouvé sur la façon de boucler un hachage. Quelle serait la bonne chose à faire ici ? Peut-être utiliser un tableau, mais avec les deux valeurs, séparées par un espace ?

Ou ai-je oublié quelque chose d'évident ?

255voto

VertigoRay Points 361

La sténographie n'est pas préférée pour les scripts ; elle est moins lisible. L'opérateur %{} est considéré comme un raccourci. Voici comment il doit être utilisé dans un scripts pour des raisons de lisibilité et de réutilisation :

Configuration des variables

PS> $hash = @{
    a = 1
    b = 2
    c = 3
}
PS> $hash

Name                           Value
----                           -----
c                              3
b                              2
a                              1

Option 1 : GetEnumerator()

Note : préférence personnelle ; la syntaxe est plus facile à lire.

La méthode GetEnumerator() serait exécutée comme indiqué :

foreach ($h in $hash.GetEnumerator()) {
    Write-Host "$($h.Name): $($h.Value)"
}

Sortie :

c: 3
b: 2
a: 1

Option 2 : Clés

La méthode des clés serait appliquée comme indiqué :

foreach ($h in $hash.Keys) {
    Write-Host "${h}: $($hash.$h)"
}

Sortie :

c: 3
b: 2
a: 1

Informations complémentaires

Attention au tri de vos hashtable...

Objet trié peut le transformer en tableau :

PS> $hash.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object

PS> $hash = $hash.GetEnumerator() | Sort-Object Name
PS> $hash.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

Cette méthode et d'autres boucles PowerShell sont disponibles sur mon blog.

117voto

Andy Arismendi Points 16501

La réponse de Christian fonctionne bien et montre comment vous pouvez parcourir en boucle chaque élément de la table de hachage à l'aide de la fonction GetEnumerator méthode. Vous pouvez également effectuer une boucle à l'aide de la méthode keys propriété. Voici un exemple :

$hash = @{
    a = 1
    b = 2
    c = 3
}
$hash.Keys | % { "key = $_ , value = " + $hash.Item($_) }

Sortie :

key = c , value = 3
key = a , value = 1
key = b , value = 2

10voto

Steven Penny Points 18523

Vous pouvez également le faire sans variable

@{
  'foo' = 222
  'bar' = 333
  'baz' = 444
  'qux' = 555
} | % getEnumerator | % {
  $_.key
  $_.value
}

8voto

Eelco L. Points 51

Je préfère cette variante de la méthode de l'énumérateur avec un pipeline, car il n'est pas nécessaire de faire référence à la table de hachage dans le foreach (testé dans PowerShell 5) :

$hash = @{
    'a' = 3
    'b' = 2
    'c' = 1
}
$hash.getEnumerator() | foreach {
    Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}

Sortie :

Key = c and Value = 1
Key = b and Value = 2
Key = a and Value = 3

Les objets n'ont pas été délibérément triés en fonction de leur valeur ; l'énumérateur renvoie simplement les objets dans l'ordre inverse.

Mais comme il s'agit d'un pipeline, je peux maintenant trier les objets reçus de l'énumérateur en fonction de leur valeur :

$hash.getEnumerator() | sort-object -Property value -Desc | foreach {
  Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}

Sortie :

Key = a and Value = 3
Key = b and Value = 2
Key = c and Value = 1

7voto

CB. Points 24549

A propos du bouclage d'un hachage :

$Q = @{"ONE"="1";"TWO"="2";"THREE"="3"}
$Q.GETENUMERATOR() | % { $_.VALUE }
1
3
2

$Q.GETENUMERATOR() | % { $_.key }
ONE
THREE
TWO

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X