Цикл через хэш или использование массива в PowerShell?
Я использую этот (упрощенный) кусок кода для извлечения набора таблиц из SQL Server с помощью 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
}
Он отлично работает, но теперь некоторые таблицы должны быть извлечены через взгляды, а некоторые нет. Поэтому мне нужна структура данных что-то вроде этого:
"Page" "vExtractPage"
, "ChecklistItemCategory" "ChecklistItemCategory"
, "ChecklistItem" "vExtractChecklistItem"
Я смотрел на хэши, но я не нашел ничего о том, как перебрать хэш. Что было бы правильным сделать здесь? Возможно просто использовать массив, но с обоими значениями, разделенными космос?
или я упускаю что-то очевидное?
6 ответов:
ответ Кристиана работает хорошо и показывает, как вы можете перебирать каждый элемент хэш-таблицы с помощью
GetEnumerator
метод. Вы также можете выполнить цикл с помощьюkeys
собственность. Вот пример, как:$hash = @{ a = 1 b = 2 c = 3 } $hash.Keys | % { "key = $_ , value = " + $hash.Item($_) }
выход:
key = c , value = 3 key = a , value = 1 key = b , value = 2
Стенография не является предпочтительной для скриптов; она менее читаема. Оператор %{} считается сокращенным. Вот как это должно быть сделано в скрипте для чтения и повторного использования:
Переменной Установки
PS> $hash = @{ a = 1 b = 2 c = 3 } PS> $hash Name Value ---- ----- c 3 b 2 a 1
Вариант 1: GetEnumerator ()
Примечание: личные предпочтения; синтаксис легче читать
метод GetEnumerator() будет выполнен следующим образом:
foreach ($h in $hash.GetEnumerator()) { Write-Host "$($h.Name): $($h.Value)" }
выход:
c: 3 b: 2 a: 1
Вариант 2: Ключи
метод ключей будет выполнен так, как показано:
foreach ($h in $hash.Keys) { Write-Host "${h}: $($hash.Item($h))" }
выход:
c: 3 b: 2 a: 1
дополнительная информация
будьте осторожны при сортировке хэш-таблицы... Sort-Object может изменить его в массив:
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
о цикле через хэш:
$Q = @{"ONE"="1";"TWO"="2";"THREE"="3"} $Q.GETENUMERATOR() | % { $_.VALUE } 1 3 2 $Q.GETENUMERATOR() | % { $_.key } ONE THREE TWO
вы также можете сделать это без переменной
@{ 'foo' = 222 'bar' = 333 'baz' = 444 'qux' = 555 } | % getEnumerator | % { $_.key $_.value }
вот еще один быстрый способ, просто используя ключ в качестве индекса в хэш-таблице, чтобы получить значение:
$hash = @{ 'a' = 1; 'b' = 2; 'c' = 3 }; foreach($key in $hash.keys) { Write-Host ("Key = " + $key + " and Value = " + $hash[$key]); }
Если вы используете PowerShell v3, вы можете использовать JSON вместо хэш-таблицы и преобразовать ее в объект с помощью Конвертировать-FromJson:
@' [ { FileName = "Page"; ObjectName = "vExtractPage"; }, { ObjectName = "ChecklistItemCategory"; }, { ObjectName = "ChecklistItem"; }, ] '@ | Convert-FromJson | ForEach-Object { $InputFullTableName = '{0}{1}' -f $TargetDatabase,$_.ObjectName # In strict mode, you can't reference a property that doesn't exist, #so check if it has an explicit filename firest. $outputFileName = $_.ObjectName if( $_ | Get-Member FileName ) { $outputFileName = $_.FileName } $OutputFullFileName = Join-Path $OutputDirectory $outputFileName bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption }