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] это обеспечивает дружественное представление.)