Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Существует множество способов использования переменных в строках. Я называю это подстановкой переменных, но имею в виду случаи, когда вы хотите отформатировать строку для вставки значений из переменных. Это то, что я часто объясняю новым скриптерам.
Примечание.
Оригинальная версия этой статьи появилась в блоге, написанном @KevinMarquette. Команда PowerShell благодарит Кевина за предоставление этого содержимого нам. Пожалуйста, ознакомьтесь с его блогом на PowerShellExplained.com.
Конкатенация
Первый класс методов можно называть объединением. Это в основном заключается в том, чтобы взять несколько строк и объединить их вместе. Существует длинная история использования объединения для создания форматированных строк.
$name = 'Kevin Marquette'
$message = 'Hello, ' + $name
Объединение работает хорошо, если нужно добавить только несколько значений. Это может быстро усложниться.
$first = 'Kevin'
$last = 'Marquette'
$message = 'Hello, ' + $first + ' ' + $last + '.'
Этот простой пример уже становится сложнее читать.
Подстановка переменных
PowerShell имеет еще один вариант, который проще. Переменные можно указать непосредственно в строках.
$message = "Hello, $first $last."
Тип кавычек, используемых вокруг строки, имеет разницу. Двойная строка с кавычками разрешает подстановку, но одна строка с кавычками не поддерживается. Есть время, когда вы хотите один или другой, чтобы у вас был вариант.
Подстановка команд
Когда вы начинаете пытаться вставить значения свойств в строку, все становится немного сложнее. Вот в чем многие новички спотыкаются. Сначала позвольте мне показать вам, что, по их мнению, должно работать (и на первый взгляд почти кажется, как будто оно должно).
$directory = Get-Item 'C:\windows'
$message = "Time: $directory.CreationTime"
Вы рассчитывали получить CreationTime от $directory, но вместо этого получаете Time: C:\windows.CreationTime в качестве значения. Причина заключается в том, что этот тип подстановки видит только базовую переменную. Он рассматривает период как часть строки, чтобы он перестал разрешать значение более глубоко.
Так получилось, что этот объект дает строку в качестве значения по умолчанию, когда он включен в строку.
Некоторые объекты дают имя типа, например System.Collections.Hashtable. Просто на что-то обратить внимание.
PowerShell позволяет выполнять команды внутри строки с особым синтаксисом. Это позволяет получить свойства этих объектов и выполнить любую другую команду, чтобы получить значение.
$message = "Time: $($directory.CreationTime)"
Это работает отлично для некоторых ситуаций, но она может стать такой же запутанной, как объединение, если у вас всего несколько переменных.
Выполнение команды
Команды можно выполнять внутри строки. Несмотря на то, что у меня есть этот вариант, я не люблю это. Оно быстро захламляется, и его трудно отлаживать. Либо я выполняю команду и сохраняю в переменную, либо использую строку формата.
$message = "Date: $(Get-Date)"
Строка форматирования
В .NET есть способ форматирования строк, с которыми можно легко работать. Сначала я покажу вам статический способ, а затем расскажу, как использовать горячую клавишу PowerShell для достижения того же результата.
# .NET string format string
[string]::Format('Hello, {0} {1}.',$first,$last)
# PowerShell format string
'Hello, {0} {1}.' -f $first, $last
То, что происходит здесь, заключается в том, что строка анализируется для маркеров {0} и {1}, а затем использует это число для выбора из указанных значений. Если вы хотите повторить одно значение в строке, можно повторно использовать это число значений.
Чем сложнее получается строка, тем больше значения вы получаете из этого подхода.
Форматирование значений в виде массивов
Если строка формата слишком длинна, вы можете сначала поместить значения в массив.
$values = @(
"Kevin"
"Marquette"
)
'Hello, {0} {1}.' -f $values
Это не распаковка, потому что я передаю целый массив, но идея аналогична.
Расширенное форматирование
Я намеренно назвал их как исходящие из .NET, потому что есть много вариантов форматирования уже хорошо задокументированных на нем. Существуют встроенные способы форматирования различных типов данных.
"{0:yyyyMMdd}" -f (Get-Date)
"Population {0:N0}" -f 8175133
20211110
Population 8,175,133
Я не собираюсь вдаваться в детали, но хотел вас уведомить, что это очень мощный механизм форматирования, если вам это потребуется.
Присоединение строк
Иногда вы действительно хотите объединить список значений вместе. Существует оператор -join, который может сделать это для вас. Он даже позволяет указать символ для соединения между строками.
$servers = @(
'server1'
'server2'
'server3'
)
$servers -join ','
Если вы хотите использовать -join некоторые строки без разделителя, вам нужно указать пустую строку ''.
Но если это все, что вам нужно, есть более быстрый вариант.
[string]::Concat('server1','server2','server3')
[string]::Concat($servers)
Кроме того, стоит указать, что также можно -split строки.
Join-Path
Хотя это часто упускают из виду, командлет прекрасно подходит для создания пути к файлу.
$folder = 'Temp'
Join-Path -Path 'C:\windows' -ChildPath $folder
Отличное в этом то, что он правильно обрабатывает обратные слеши, когда объединяет значения. Это особенно важно, если вы принимаете значения из пользователей или файлов конфигурации.
Это также хорошо подходит для Split-Path и Test-Path. Я также освещаю их в своей публикации о чтении и сохранении в файлах.
Строки — это массивы
Необходимо упомянуть о добавлении строк здесь, прежде чем продолжить. Помните, что строка — это всего лишь массив символов. При добавлении нескольких строк вместе создается новый массив каждый раз.
Ознакомьтесь с этим примером:
$message = "Numbers: "
foreach($number in 1..10000)
{
$message += " $number"
}
Это выглядит очень просто, но то, что вы не видите, заключается в том, что каждый раз при добавлении строки в $message создается новая строка. Память выделяется, данные копируются, а старый удаляется.
Небольшая проблема, когда это делается только несколько раз, но цикл, как этот, действительно выявил бы проблему.
StringBuilder
StringBuilder также очень популярен для создания больших строк из множества небольших строк. Причина заключается в том, что он просто собирает все строки, которые вы добавляете в него, и объединяет их только в конце при извлечении значения.
$stringBuilder = New-Object -TypeName "System.Text.StringBuilder"
[void]$stringBuilder.Append("Numbers: ")
foreach($number in 1..10000)
{
[void]$stringBuilder.Append(" $number")
}
$message = $stringBuilder.ToString()
Опять же, это то, к чему я обращаюсь за помощью к .NET. Я больше не часто использую его, но хорошо знать, что оно там.
Разграничение с фигурными скобками
Используется для добавления суффикса к строке. Иногда переменная не имеет чёткой границы между словами.
$test = "Bet"
$tester = "Better"
Write-Host "$test $tester ${test}ter"
Спасибо Redditor u/real_parbold за это.
Ниже приведен альтернативный подход.
Write-Host "$test $tester $($test)ter"
Write-Host "{0} {1} {0}ter" -f $test, $tester
Я лично использую форматную строку для этого, но полезно знать на случай, если вы встретите это в реальных условиях.
Поиск и замена маркеров
Хотя большинство этих функций снижает необходимость разрабатывать собственное решение, в некоторых случаях могут встречаться большие файлы шаблонов, в которых требуется заменить строки.
Предположим, что вы извлекли шаблон из файла с большим количеством текста.
$letter = Get-Content -Path TemplateLetter.txt -RAW
$letter = $letter -replace '#FULL_NAME#', 'Kevin Marquette'
У вас может быть много маркеров для замены. Этот способ заключается в использовании очень уникального маркера, который легко найти и заменить. Обычно я использую специальный символ на обоих концах, чтобы помочь его отличить.
Недавно я нашел новый способ приблизиться к этому. Я решил оставить этот раздел здесь, потому что это шаблон, который часто используется.
Замена нескольких токенов
Когда у меня есть список маркеров, которые мне нужно заменить, я принимаю более универсальный подход. Я бы поместил их в хеш-таблицу и прошёл бы по ним, чтобы произвести замену.
$tokenList = @{
Full_Name = 'Kevin Marquette'
Location = 'Orange County'
State = 'CA'
}
$letter = Get-Content -Path TemplateLetter.txt -RAW
foreach( $token in $tokenList.GetEnumerator() )
{
$pattern = '#{0}#' -f $token.key
$letter = $letter -replace $pattern, $token.Value
}
Эти маркеры можно загрузить из JSON или CSV при необходимости.
Контекст выполнения (ExecutionContext) ExpandString
Существует умный способ определить строку подстановки с одними кавычками и расширить переменные позже. Ознакомьтесь с этим примером:
$message = 'Hello, $Name!'
$name = 'Kevin Marquette'
$string = $ExecutionContext.InvokeCommand.ExpandString($message)
Вызов InvokeCommand.ExpandString в текущем контексте выполнения использует переменные в текущей области для подстановки. Ключевой вещью здесь является то, что $message можно определить очень рано, прежде чем переменные даже существуют.
Если чуть подробнее объяснить, мы можем выполнять эту подстановку многократно с различными значениями.
$message = 'Hello, $Name!'
$nameList = 'Mark Kraus','Kevin Marquette','Lee Dailey'
foreach($name in $nameList){
$ExecutionContext.InvokeCommand.ExpandString($message)
}
Продолжая развивать эту идею, можно импортировать большой шаблон электронной почты из текстового файла. Я должен поблагодарить Марк Краус за это предложение.
Все, что работает лучше всего для вас
Я поклонник подхода к форматированию строк. Я определенно делаю это с более сложными строками или если есть несколько переменных. На что-нибудь, что очень коротко, я могу использовать любой из этих.
Что-нибудь ещё?
Я многое обсудила по этому вопросу. Я надеюсь, что вы уйдете, узнав что-то новое.
Ссылки.
Если вы хотите узнать больше о методах и функциях, которые позволяют интерполяции строк, см. в следующем списке справочной документации.
- Объединение использует оператор добавления
- Замена переменных и команд следует правилам цитирования
- Форматирование производится с использованием оператора
- Присоединение строк использует оператор соединения и ссылки
Join-Path, но вы также можете ознакомиться сJoin-String - Массивы документируются в разделе О массивах
- StringBuilder — это класс .NET с собственной документацией
- Фигурные скобки в строках также охватываются правилами цитирования
- Замена маркеров использует оператор замены
- Метод
$ExecutionContext.InvokeCommand.ExpandString()содержит справочную документацию по API .NET
PowerShell