Перейти к содержимому

Как использовать циклы While и Foreach в Powershell Foreach на примерах

Основное предназначение циклов в Powershell, так же как и в других языках, выполнение итераций. Проще говоря они помогают выполнять одну и ту же инструкцию для разных значений. Отличительной чертой циклов в Powershell является их количество, всего их 7:

  1. Foreach-Object — команда;
  2. Foreach — выражение;
  3. Foreach() — метод;
  4. For — цикл;
  5. While — цикл;
  6. Do-While — цикл;
  7. Do-Until — цикл.

Каждый из них по своему выполняет итерации. Само понятие итераций обозначает повторное выполнение действий, например команд. Иногда можно услышать слова «итерируемый объект» или «итератор», которые обозначают объект проходящий через цикл.

Foreach-Object

Foreach-Object относится к командам, а не циклам. Чаще всего мы с ним работаем через конвейер.

Итерации

Так же, как и во многих других командах Powershell у Foreach-Object есть параметр InputObject, через который помещается объект для перебора. На примере ниже этот объект в виде массива с числами:

$PSitem это переменная, которая хранит текущее значение массива. Мы ее выводим через параметр Process, в котором можно дополнить логику командами или условиями. Переменная $PSitem аналогична такому написанию $_ .

Если вы имеете опыт работы с Powershell, то чаще использовали с конвейером:

По сути в команде выше происходит то же самое, просто в функциях и командах есть возможность установить параметр, который принимает значения по умолчанию из конвейера. Я так же добавил вывод только имени, так как у объекта из Get-Service есть такое свойство.  Параметры, которые принимают значения из конвейера можно увидеть так:

Когда вам нужно использовать больше логики зажимайте shift + enter для перехода на новую строчку, если работаете из консоли. Скрипт ниже получает список процессов, передает их через конвейер, где через наш командлет происходит анализ время отклика CPU с выводом результата:

Можно использовать и другой синтаксис. Так я получу имена сервисов:

Я не видел, что бы кто-то использовал такой синтаксис, но он возможен. На примере ниже я преобразую строки в массив двумя способами:

Split — это метод, который преобразует строку в массив используя указанный разделитель (в нашем случае запятая). Методы и свойства, доступные у объекта, можно увидеть через Get-Member:

Сохранение через переменные

Результат этого командлета, так же как и любого другого можно сохранить в переменную и использовать дальше:

Алиасы

У этой команды есть алиасы foreach и знак %:

Обратите внимание, что использование следующего синтаксиса приведет к ошибке:

Связано это с тем, что в Powershell работает командлет и метод с одним именем. Каждый из них имеет свой синтаксис и вызывая foreach без конвейера мы используем метод. Он будет разобран следующим.

ForEach

Этот цикл, в отличие от предыдущего командлета, не будет работать через конвейер. Если вы попытаетесь использовать этот метод через конвейер, то будет использован командлет.

Итерации

Это самый простой цикл Powershell, который переходит от одного значения объекта к другому. Синтаксис следующий:

  • $item — хранит текущий элемент из $array. Эту переменную можно вызвать в ScriptBlock;
  • $array — это любая коллекция, из которой нужно получить значения;
  • Scriptblock — это область для написания сценария и остальной логики.

Для примера с foreach в Powershell выполним перебор значений массива:

Так же как и в предыдущем случае каждый новое действие в ScriptBlock должно выполняться с новой строчки:

Выше было написано, что мы не можем использовать конвейер, но исключение такое написание:

Как вы можете догадаться — это не работа цикла с конвейером, а просто передача массива.

Использование с командами

Как уже писалось выше не стоит использовать метод Powershell foreach через конвейер. Например так мы можем получить список PSProvider:

Можно добавлять выражение в сам цикл, но такой подход как минимум понизит читаемость кода. Самое главное экранировать выражение круглыми скобками:

На примере ниже пример использования цикла и командлета с одни и тем же результатом:

Как видно в случае с командой мы оперируем переменной $PSItem, а с циклом $service, так как мы ее определили еще в начале.

Работа с диапазоном или range

В Powershell можно легко указать диапазон численных значений. Я могу создать массив из чисел с 1 до 10 так:

Так же можно использовать и в итерациях:

Continue и break

Одним из отличий работы с foreach от аналогичной команды является возможность использования contnue и break.

Оператор continue минует выполнение оставшейся части скрипта после своего выполнения. На примере ниже есть два массива и если в одном из них будут встречаться одинаковые числа, то они не будут выведены:

В отличие от continue break останавливает итерации полностью. Его удобно использовать, когда мы ищем нужное значение и нам нужно остановить итерации после его нахождения:

Вложенные

Когда у нас есть массив массивов может потребоваться использовать вложенные циклы Powershell. Само их использование не должно вызывать труда, но если вы попробуете использовать операторы break и continue это сработает иначе:

Как вы видите на примере выше у нас остановился только внутренний цикл. Если нужно избежать таких ситуаций используйте OUTER:

Переменные

В этом типе цикла доступны три специальных переменных:

  • $foreach.MoveNext() — переход к следующему элементу;
  • $foreach.current — текущий элемент;
  • $foreach.reset() — обнуляет итерацию. Перебор начнется заново, что приведет к бесконечному циклу.

Такие возможности есть во многих языках программирования, но мне тяжело вспомнить ситуации что бы я их использовал. Для примера ниже мы используем массив чисел с 1 по 10. Самое первое число 1 будет выведено, после чего будет пропущено следующее:

$current просто выведет ту же переменную, объявленную в цикле:

Сравнение ForEach и команды ForEach-Object

Foreach ForEach-Object
Загружает все элементы коллекции Загружает только один элемент в память через конвейер
Использует больше памяти из-за полной загрузки массивов Меньшее использование памяти из-за одного элемента
С небольшим объемом массивов работает быстрее Работает медленнее
Нельзя использовать через конвейер. Это не приведет к ошибке, но будет использован алиас командлета Можно использовать конвейер или параметр InputObject
Поддерживаются методы break и continue Нельзя прервать используя методы contiinue и break

Скорость работы обоих этих методов можно увидеть через следующие скрипты:

Метод foreach()

В версии Powershell 4.0 появился метод foreach() для поддержки DSC.  Он немного отличается синтаксисом и подходом от описаны выше. Более простой способ понять, как он работает это посмотреть на его синтаксис:

Как я прочитал этот метод предназначен для работы только с коллекциями и по идеи такой способ должен привести к ошибке:

На всякий случай я бы советовал преобразовывать такие данные в массив:

Работа с командами

Работы с командами не должна вызывать сложности. Для примера так мы получим список имен сервисов, которые остановлены:

Самое главное экранировать результат команды в скобки или выполнять метод для переменной, которая уже хранит значения.

Еще один пример с сервисами:

for

В Powershell есть еще один способ итераций через for. Его отличие в том, что мы можем изменять основной объект до выполнения ScriptBlock. Синтаксис следующий:

Для примера получим числа с 1 по 10:

Поясню момент, который мог быть вызван написанием $i++, все следующие действия одинаковы, но не все сработают в этом цикле:

Вы можете изменять несколько объектов:

В итерациях вы можете использовать любой тип данных, не только цифры:

Вы можете пропустить любую часть этого цикла, но если ничего не будет указано получится бесконечный цикл:

Возможно использовать этот цикл с командлетами, но пример высосан из пальца:

Операторы break и continue работают так же.

While

Как можно было увидеть выше мы рассматривали циклы, которые перебирали элементы массивов, но существует еще один тип позволяющий управлять этим процессом более гибко. Для примера нам может понадобится выполнять функцию, командлет или скрипт до тех пор пока мы не получим нужны результат и для этого можно использовать While:

Пример выше работает до тех пор, пока переменная $a меньше или равна 10 или, другими словами, пока значение в скобках не станет True.

Более понятный пример это с утилитой ping. Когда мы потеряли доступ к интернету или упал сервер, то мы запускаем команду с ключом -t и она работает до тех пор пока мы не остановим этот процесс руками нажав Ctrl+c. Такая работа в Powershell относится к бесконечным циклам и на примере выглядит так:

Все эти операции можно выполнить и с foreach, но это плохая практика. Например так можно реализовать аналогичный вечный цикл с for:

Break и continue

Ключевой момент работы с while это использование break, который остановит итерации. Мы пинговали сайт, но останавливали итерации руками и что бы этого не делать в дальнейшем нужно добавить условие при котором будет выполнен break:

Очень важно хорошо продумывать логику остановки скрипта. Вечные циклы, которые могут работать в полноценных сриптах, программах и планировщиках будет очень тяжело отлавливать.

Такие итерации останавливают либо методом break, либо счетчиком, который был показан в первом примере и ниже. Если мы будем использовать счетчик и continue, который пропускает выполнения условия, то тоже можем получить вечный цикл:

Я не помню, что бы я хоть раз использовал continue в реальных задачах, но стоит помнить о существовании такой возможности.

Командлеты

Мы можем выполнять команду в условиях и объявлять в ней переменную для дальнейшего использования:

Do и While

Отличие работы этого цикла от предыдущего в том, что он проверяет условия после выполнения операций, а не до. Из-за этого, если условие изначально равно $False, цикл будет выполнен один раз:

Или поставим заведомо ложные условия при котором предыдущий цикл не стал бы работать:

Такие итерации можно использовать со случаями, когда от пользователя ожидается выбор действий:

Do Until

Предыдущий цикл выполняет итерации до тех пор, пока главное условие равняется $True. Цикл Do Until имеет такой же синтаксис, но работает до тех пор пока условие не станет $True, то есть пока оно $False:

https://fixmypc.ru/post/kak-rabotat-s-tsiklami-v-powershell-foreach-object-i-while-na-primerakh/

Опубликовано вPowershell

Ваш комментарий будет первым

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *