Powershell выводит элементы массива при интерполяции в двойных кавычках
Я нашел некоторое странное поведение в Powershell, окружающих массивы и двойные кавычки. Если я создаю и печатаю первый элемент в массиве, например:
$test = @('testing')
echo $test[0]
Output:
testing
все работает нормально. Но если я помещу вокруг него двойные кавычки:
echo "$test[0]"
Output:
testing[0]
оценивалась только переменная $test, а маркер массива [0] рассматривался буквально как строка. Простое исправление-просто избежать интерполяции переменных массива в двойных кавычках или сначала назначить их другой переменной. но я было интересно, является ли это поведение преднамеренным?
3 ответов
поэтому, когда вы используете интерполяцию, по умолчанию она интерполирует только следующую переменную в toto. Поэтому, когда вы это делаете:
"$test[0]"
он видит $test как следующую переменную, он понимает, что это массив и что у него нет хорошего способа отображения массива, поэтому он решает, что не может интерполировать и просто отображает строку как строку. Решение состоит в том, чтобы явно указать powershell, где начинается бит для интерполяции и где он останавливается:
"$($test[0])"
обратите внимание, что это поведение является одной из моих основных причин использования форматированных строк вместо того, чтобы полагаться на интерполяцию:
"{0}" -f $test[0]
в таких случаях нужно делать:
echo "$($test[0])"
Другой альтернативой является использование форматирования строк
echo "this is {0}" -f $test[0]
обратите внимание, что это будет иметь место, когда вы получаете доступ к свойствам в строках. Как "$a.Foo"
- должно быть написано как "$($a.Foo)"
полезный ответ EBGreen содержит эффективные решений, но только при беглом объяснение of интерполяция строк PowerShell (расширение строк):
-
переменные в целом может быть встроен напрямую внутри
"..."
(дважды в кавычках; напротив, один-в кавычках ('...'
), как и во многих других языках, для литерал содержание).это относится как к регулярным переменным, так и к переменным, ссылающимся на определенное пространство имен; например:
"var contains: $var"
,"Path: $env:PATH"
если первый символ после имя переменной может быть ошибочно принято за часть имени, которое, в частности, включает
:
- использовать{...}
вокруг имени переменной значения, например:"${var}"
,"${env:PATH}"
до использовать
$
как литерал, вы должны избежать его с`
, escape-символ PowerShell; например:"Variable `$var"
-
любые символы после в имя переменной, в том числе
[
и.
трактуется как литерал часть строки, так для того чтобы на встроенные переменные ($var[0]
) или свойства ($var.Count
), вам нужен$(...)
, the подвыражения оператор (фактически$(...)
позволяет вставлять весь заявления); например:"1st element: $($var[0])"
"Element count: $($var.Count)"
-
Stringification (преобразование в строку) применяется к любому значению переменной / результату оценки, который еще не является строка:
-
предостережение: если можно применить форматирование, зависящее от культуры, PowerShell выбирает инвариант культура, который во многом совпадает с US-английское форматирование даты и номера; то есть даты и числа будут представлены в US-like формате (например, формат первого месяца и
.
в качестве десятичного знака). -
по сути,
.ToString()
метод называется на любой возникший нестроковых объектов или коллекции (строго говоря, это.psobject.ToString()
, который переопределяет.ToString()
в некоторых случаях, особенно для массивов / коллекций и пользовательских объектов PS)- обратите внимание, что это не то же представление, которое вы получаете, когда выводите переменную или выражение напрямую, и многие типы имеют нет значимые строковые представления по умолчанию - они просто возвращают свой полный тип имя.
Тем не менее, вы можете встроить$(... | Out-String)
чтобы явно применить форматирование вывода PowerShell по умолчанию.
- обратите внимание, что это не то же представление, которое вы получаете, когда выводите переменную или выражение напрямую, и многие типы имеют нет значимые строковые представления по умолчанию - они просто возвращают свой полный тип имя.
для более всестороннего обсуждения струнификации см. ответ шахты.
-
предостережение: если можно применить форматирование, зависящее от культуры, PowerShell выбирает инвариант культура, который во многом совпадает с US-английское форматирование даты и номера; то есть даты и числа будут представлены в US-like формате (например, формат первого месяца и
как говорится, используя -f
, оператор форматирования строк (<format-string> -f <arg>[, ...]
) это альтернатива в строку интерполяция, которая отделяет литеральные части строки от переменных частей:
'1st element: {0}; count: {1:x}' -f $var[0], $var.Count
Примечание использование
'...'
на LHS, потому что строка формата (шаблон) сама по себе является литерал. Используя'...'
в этом случае является хорошей привычкой для формирования, как сигнализировать о намерении использовать буквальное содержимое, так и для способности вставлять$
символов без экранирования.в дополнение к простые позиционные заполнители (
{0}
для 1-го аргумента.{1}
за 2-й, ...), вы можете дополнительно осуществлять больше управление форматированием преобразования в строку; в приведенном выше примереx
запрос hex представление числа.
Доступные форматы см. В документации платформы .NET frameworkString.Format
метод, которым-f
оператора на.ошибка:
-f
имеет высокую приоритет, так что заключите выражения RHS, отличные от простого индекса или доступа к свойствам в(...)
, например,'{0:N2}' -f 1/3
не будет работать по назначению, только'{0:N2}' -f (1/3)
предостережения: есть важные различия между Строковой интерполяцией и
-f
- см. под.
в отличие от интерполяции внутри "..."
на -f
оператор is чувствительный к культуре:
поэтому следующие два, казалось бы, эквивалентных утверждения do не дайте тот же результат:
PS> [cultureinfo]::CurrentCulture = 'fr'; $n = 1.2; "interpolated: $n"; '-f: {0}' -f $n
interpolated: 1.2
-f: 1,2
обратите внимание, как только -f
- отформатированная команда уважала французов (fr
) знак десятичной дроби (,
).
Опять же, см. ранее ответ для всестороннего рассмотрения того,когда PowerShell является и не является чувствительным к культуре.
в отличие от интерполяции внутри "..."
, -f
stringifies массивы как <type-name>[]
:
PS> $arr = 1, 2, 3; "`$arr: $arr"; '$arr: {0}' -f (, $arr)
$arr: 1 2 3
$arr: System.Object[]
Примечание: (, ...)
обертывания $arr
в вспомогательном массиве, который гарантирует, что -f
видит выражение как одиночный, массив-значение операнд; по умолчанию элементы массива будут рассматриваться как отдельные операнды.
обратите внимание, как "..."
интерполяция создала разделенный пробелом список stringification всех элементов массива, тогда как -f
-форматирование печатается только имя типа массива.
(Как уже говорилось,$arr
внутри "..."
эквивалентно:(1, 2, 3).psobject.ToString()
и это типа [psobject]
это обеспечивает дружественное представление.)