Powershell выводит только первый символ
У меня есть следующий набор данных:
id|selectedquery|
1|SELECT fieldX FROM tableA|
2|SELECT fieldY FROM tableB|
этот набор данных используется в следующем коде
$rows=($dataSet.Tables | Select-Object -Expand Rows)
$i=0
foreach ($row in $rows)
{
#Write-Output $rows.selectquery[$i].length
$query = $rows.selectquery[$i]
#Write-Output $rows.selectquery[$i]
--doing some stuff--
$i++
}
Часто дает мне только первый символ значения в поле
selectedquery
будучи буквой «S».
Когда я удаляю
[$i]
из
$rows.selectquery
он возвращает мне (по понятным причинам) несколько записей. Если я верну [$i] после
$rows.selectquery[$i]
все шло хорошо.
Кто-нибудь может объяснить такое поведение?
2 ответа
Вы захотите сослаться на
SelectQuery
собственность на любом
$row
или же
$rows[$i]
- не весь
$rows
коллекция:
$row.SelectQuery
# or
$rows[$i].SelectQuery
Полезный ответ Матиаса показывает, как лучше всего решить вашу конкретную проблему.
Что касается того, что произошло:
Вы - непреднамеренно - использовали функцию перечисления членов PowerShell, когда использовали
$rows.selectquery
; то есть, хотя
$rows
это коллекция , которая сама по себе не имеет
.selectquery
свойство, PowerShell обращалась к этому свойству для каждого элемента коллекции и возвращала результирующие значения в виде массива .
Ловушка является то , что если коллекция имеет только один элемент, то возвращаемое значение не массив - это только один и только значение свойства элемента сам по себе .
Хотя это аналогично тому, как работает конвейер (один выходной объект захватывается сам по себе, если назначен переменной, в то время как два или более неявно собираются в массив), это несколько нелогично в контексте перечисления членов:
- Другими словами,
$collection.SomeProperty
эквивалентно$collection | ForEach-Object { $_.SomeProperty }
а не , что было бы больше смысла, потому что он всегда возвращает массив (коллекцию),$collection.ForEach('SomeProperty')
- В выпуске GitHub № 6802 обсуждается эта проблема.
Хотя такое поведение часто не вызывает проблем, поскольку PowerShell предлагает унифицированную обработку скаляров и коллекций (например,
(42)[0]
, такой же как
42
сам; см. этот ответ ), проблема возникает, если возвращаемое единственное значение оказывается строкой , потому что при индексации строки возвращаются ее символы .
- Обходной путь : приведите к перед применением индекса:
-
([array] $rows.selectquery)[0]
-
Простой пример :
# Multi-element array.
[array] $rows1 = [pscustomobject] @{ selectquery = 'foo' },
[pscustomobject] @{ selectquery = 'bar' }
# Single-element array:
[array] $rows2 = [pscustomobject] @{ selectquery = 'baz' }
# Contrast member enumeration + index access between the two:
[pscustomobject] @{
MultiElement = $rows1.selectquery[0]
SingleElement = $rows2.selectquery[0]
SinglElementWithWorkaround = ([array] $rows2.selectquery)[0]
}
Вышеупомянутое дает следующее:
MultiElement SingleElement SinglElementWithWorkaround
------------ ------------- --------------------------
foo b baz
Как видите, многоэлементный массив работал так, как ожидалось, потому что перечисление членов тоже вернуло массив, а одноэлементный массив привел к единственной строке
'baz'
возвращаются и
'baz'[0]
возвращает свой первый символ ,
'b'
.
Трансляция на
[array]
сначала избегает этой проблемы (
([array] $rows2.selectquery)[0]
).
- С использованием
@(...)
, оператор подвыражения массива -@($rows.selectquery)[0]
- это еще один вариант, но для эффективности его следует использовать только в командах (например,@(Get-ChildItem -Name *.txt)[0]
) а не выражения , как в данном случае.)