Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Назначение: Windows PowerShell 2.0, Windows PowerShell 3.0
РАЗДЕЛ
about_Foreach
КРАТКОЕ ОПИСАНИЕ
Содержит описание команды языка, позволяющей перебирать все элементы в коллекции.
ПОДРОБНОЕ ОПИСАНИЕ
Оператор Foreach (называемый также циклом Foreach) является языковой конструкцией для пошагового перемещения (итерации) по последовательности значений в коллекции элементов.
Самым простым и наиболее часто используемым типом коллекции, по которой производится перемещение, является массив. Обычно в цикле Foreach одна или несколько команд выполняются применительно к каждому элементу массива.
Синтаксис
Ниже показан синтаксис оператора ForEach.
foreach ($<item> in $<collection>){<statement list>}
Упрощенный синтаксис
Начиная с версии Windows PowerShell® 3.0 синтаксис с ключевыми словами языка, например Where и ForEach, был упрощен. Операторы сравнения, которые применяются к элементам коллекции, рассматриваются как параметры. К элементам коллекции можно применять метод, не включая его в блок сценария и не добавляя автоматическую переменную «$_.». Рассмотрим следующие два примера:
dir cert:\ -Recurse | foreach GetKeyAlgorithm
dir cert:\ -Recurse | foreach {$_.GetKeyAlgorithm()}
Хотя обе команды работают, первая возвращает результаты без использования блока сценария или автоматической переменной «$_.». Метод GetKeyAlgorithm рассматривается как параметр оператора ForEach. Первая команда возвращает те же результаты, но без ошибок, так как упрощенный синтаксис не пытается вернуть результаты для элементов, к которым не был применен указанный аргумент.
В этом примере свойство Description командлета Get-Process передается в качестве аргумента параметра оператора ForEach. Результаты представляют собой описания активных процессов.
Get-Process | ForEach Description
Оператор Foreach за пределами конвейера команд
В заключаемой в круглые скобки части оператора Foreach указываются переменная и коллекция для перебора. При выполнении цикла Foreach среда Windows PowerShell автоматически создает переменную ($<элемент>). Перед каждой итерацией в цикле переменной присваивается значение в коллекции. Блок после оператора Foreach {<список_операторов>} содержит набор команд, выполняемых применительно к каждому элементу коллекции.
Примеры
Например, цикл Foreach в приведенном ниже примере отображает значения в массиве $letterArray.
$letterArray = "a","b","c","d"
foreach ($letter in $letterArray)
{
Write-Host $letter
}
В этом примере создается массив $letterArray, который затем инициализируется строковыми значениями «a», «b», «c» и «d». При первом выполнении оператора Foreach переменная $letter устанавливается равной первому элементу в массиве $letterArray («a»). Затем буква «a» отображается с помощью командлета Write-Host. При следующей итерации цикла переменной $letter присваивается значение «b» и т. д. После того как цикл Foreach отобразит букву «d», Windows PowerShell выходит из цикла.
Чтобы оператор Foreach выполнялся как команда в командной строке Windows PowerShell, он должен быть представлен в одной строке целиком. Оператор Foreach не обязательно должен быть представлен в одной строке целиком, если команда помещена в файл сценария PS1.
Операторы Foreach могут также использоваться вместе с командлетами, возвращающими коллекции элементов. В приведенном ниже примере оператор Foreach выполняет перебор элементов списка, возвращаемого командлетом Get-ChildItem.
foreach ($file in Get-ChildItem)
{
Write-Host $file
}
Пример можно усовершенствовать с помощью оператора If для ограничения возвращаемых результатов. В примере ниже оператор Foreach выполняет те же операции в цикле, что и в предыдущем примере, но здесь добавлена инструкция If, ограничивающая результаты файлами, размер которых превышает 100 килобайт (КБ).
foreach ($file in Get-ChildItem)
{
if ($file.length -gt 100KB)
{
Write-Host $file
}
}
В этом примере цикл Foreach использует свойство переменной $file для выполнения операции сравнения ($file.length -gt 100KB). Переменная $file содержит все свойства в объекте, возвращаемом командлетом Get-ChildItem. Поэтому может возвращаться не только имя файла. В следующем примере Windows PowerShell внутри списка операторов возвращает длину и время последнего обращения.
foreach ($file in Get-ChildItem)
{
if ($file.length -gt 100KB)
{
Write-Host $file
Write-Host $file.length
Write-Host $file.lastaccesstime
}
}
В этом примере в списке операторов не обязательно выполнять только одну команду.
Кроме того, можно использовать переменную вне цикла Foreach и увеличивать ее значение внутри цикла. В примере ниже подсчитываются файлы, размер которых превышает 100 КБ.
$i = 0
foreach ($file in Get-ChildItem)
{
if ($file.length -gt 100KB)
{
Write-Host $file "file size:" ($file.length /
1024).ToString("F0") KB
$i = $i + 1
}
}
if ($i -ne 0)
{
Write-Host
Write-Host $i " file(s) over 100 KB in the current
directory."}
else
{
Write-Host "No files greater than 100 KB in the current
directory."
}
В предыдущем примере переменной $i присваивается значение 0 вне цикла, а увеличение значения происходит внутри цикла для каждого найденного файла размером больше 100 КБ. При выходе из цикла инструкция If вычисляет значение переменной $i для отображения количества всех файлов размером более 100 КБ. Либо выводится сообщение о том, что ни одного файла размером более 100 КБ не найдено.
Предыдущий пример также демонстрирует, как форматировать результаты для длины.
($file.length / 1024).ToString("F0")
Значение делится на 1024, чтобы показать результаты в килобайтах, а не в байтах. Полученное значение далее форматируется с помощью спецификатора формата с фиксированной запятой для удаления из результата дробной части. Значение 0 спецификатора формата указывает, что дробная часть отображаться не должна.
Оператор Foreach внутри конвейера команд
Когда оператор Foreach используется в конвейере команд, Windows PowerShell использует псевдоним foreach, вызывающий команду ForEach-Object. При использовании псевдонима foreach в конвейере команд не используется синтаксическая конструкция ($<элемент> in $<коллекция>), как это делается с оператором Foreach. Это является следствием того, что эти сведения предоставляет предыдущая команда в конвейере. Синтаксис псевдонима foreach, применяемого в конвейере команд, выглядит следующим образом:
<command> | foreach {<command_block>}
Например, цикл Foreach в следующем конвейере команд отображает процессы, рабочий набор (использование памяти) которых превышает 20 мегабайт (МБ).
Команда Get-Process получает имена всех процессов на компьютере. Псевдоним Foreach выполняет команды в блоке сценария для каждого процесса в последовательности.
Оператор IF выбирает процессы с рабочим набором (WS) больше 20 мегабайт. Командлет Write-Host записывает имя процесса и ставит после него двоеточие. Он делит значение рабочего набора, которое хранится в байтах, на 1 мегабайт, чтобы получить значение рабочего набора в мегабайтах. Затем он преобразует результат из типа double в строку. Значение выводится в виде числа с фиксированной запятой с нулем десятичных знаков (F0), за которым следует пробел (« ») и «МБ».
Write-Host "Processes with working sets greater than 20 MB."
Get-Process | foreach {
if ($_.WS -gt 20MB)
{ Write-Host $_.name ": " ($_.WS/1MB).ToString("F0") MB -Separator ""}
}
Псевдоним foreach также поддерживает начальные, средние и конечные блоки команд. Начальный и конечный блоки команд выполняются один раз, а средний блок команд выполняется каждый раз, когда цикл Foreach перемещается к очередному элементу коллекции или массива.
Синтаксис псевдонима foreach, используемого в конвейере команд с начальным, средним и конечным блоками команд, выглядит следующим образом:
<command> | foreach {<beginning command_block>}{<middle
command_block>}{<ending command_block>}
В примере ниже демонстрируется использование начального, среднего и конечного блоков команд.
Get-ChildItem | foreach {
$fileCount = $directoryCount = 0}{
if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}{
"$directoryCount directories and $fileCount files"}
Начальный блок создает и инициализирует две переменные со значением 0.
{$fileCount = $directoryCount = 0}
Средний блок проверяет, является ли возвращаемый командлетом Get-ChildItem элемент каталогом или файлом.
{if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}
Если возвращаемый элемент является каталогом, значение переменной $directoryCount увеличивается на 1. Если элемент не является каталогом, на 1 увеличивается значение переменной $fileCount. Конечный блок выполняется после того, как средний блок завершает цикл и возвращает результат операции.
{"$directoryCount directories and $fileCount files"}
С помощью структуры начального, среднего и конечного блоков команд и оператора конвейера можно переписать приведенный выше пример поиска файлов размером более 100 КБ следующим образом:
Get-ChildItem | foreach{
$i = 0}{
if ($_.length -gt 100KB)
{
Write-Host $_.name "file size:" ($_.length /
1024).ToString("F0") KB
$i++
}
}{
if ($i -ne 0)
{
Write-Host
Write-Host "$i file(s) over 100 KB in the current
directory."
}
else
{
Write-Host "No files greater than 100 KB in the current
directory."}
}
В приведенном ниже примере функции, которая возвращает функции, использующиеся в сценариях и модулях сценариев, демонстрируется, как использовать метод MoveNext (работающий аналогично «skip X» в цикле For) и свойство Current переменной $foreach в блоке сценария foreach даже при наличии необычных или неединообразных определений функций, имена которых объявлены в нескольких строках. Этот пример также работает при наличии комментариев в функциях, используемых в сценарии или модуле сценария.
function Get-FunctionPosition {
[CmdletBinding()]
[OutputType('FunctionPosition')]
param(
[Parameter(Position=0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[Alias('PSPath')]
[System.String[]]
$Path
)
process {
try {
$filesToProcess = if ($_ -is [System.IO.FileSystemInfo]) {
$_
} else {
Get-Item -Path $Path
}
foreach ($item in $filesToProcess) {
if ($item.PSIsContainer -or $item.Extension -notin @('.ps1','.psm1')) {
continue
}
$tokens = $errors = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile($item.FullName,([REF]$tokens),([REF]$errors))
if ($errors) {
Write-Warning "File '$($item.FullName)' has $($errors.Count) parser errors."
}
:tokenLoop foreach ($token in $tokens) {
if ($token.Kind -ne 'Function') {
continue
}
$position = $token.Extent.StartLineNumber
do {
if (-not $foreach.MoveNext()) {
break tokenLoop
}
$token = $foreach.Current
} until ($token.Kind -in @('Generic','Identifier'))
$functionPosition = [pscustomobject]@{
Name = $token.Text
LineNumber = $position
Path = $item.FullName
}
Add-Member -InputObject $functionPosition -TypeName FunctionPosition -PassThru
}
}
} catch {
throw
}
}
}
СМ. ТАКЖЕ
about_Automatic_Variables
about_If
Foreach-Object