Когда более 30 лет назад в MS-DOS появились пакетные файлы, язык программирования BASIC был основным языком программирования для микрокомпьютеров. Оператор Goto используют в языке BASIC, чтобы упростить повторение строк кода, поэтому разработчики Microsoft добавили команду Goto к «языку» пакетных файлов с целью обеспечить функцию того же типа. В листинге 1 показан простой пакетный файл, в котором команда Goto используется для перехода к метке пакетного файла, чтобы повторить команду Echo пять раз.

Когда «язык» пакетных файлов был обновлен в Cmd.exe на платформе Windows NT, Microsoft усовершенствовала команду Call, чтобы метка в пакетном файле могла действовать как простая подпрограмма, аналогично старому оператору GOSUB в языке BASIC. В листинге 2 показан пример такого использования команды Call.

При выполнении пакетного файла в листинге 2 выводится фраза Hello, Ken, а затем End of batch file. Команда Call позволяет перейти к команде с меткой, а затем выполнение возвращается строке, следующей после команды Call. Кроме того, в подпрограммах пакетного файла нет встроенного способа передачи значений без переменных среды и неинтуитивных синтаксических приемов Cmd.exe.

Дело в том, что команды Goto и Call пакетного файла позволяют повторять строки кода, но это делается неструктурированным способом. То есть команда Goto или Call обеспечивает произвольный переход к любой метке в пакетном файле. Пакетный файл становится более сложным, использование Goto или Call в конечном итоге ведет к превращению кода в «спагетти», так как отслеживать логику пакетного файла становится все труднее.

Авторы PowerShell полностью обошли проблему «спагетти-кода». В PowerShell нет ни команды Goto, ни команды Call, потому что они не нужны. Вместо них в PowerShell появились структурированные программные инструкции, заменившие как Goto (для итерации), так и Call (для подпрограмм).

Итерации PowerShell

Итерация (или цикл) — это повторение кода. PowerShell располагает четырьмя базовыми операторами, которые повторяют выполнение строк кода в зависимости от условия: while, do while, do until и for. Четыре оператора, или конструкции цикла, фактически устраняют необходимость в команде Goto.

Когда в MS-DOS появились пакетные файлы, BASIC был основным языком программирования для микрокомпьютеров, и GOTO была незаменимой командой. К счастью, положение изменилось. Ниже показано, как while, do while, do until и for заменили традиционные команды в различных ситуациях.

Оператор While

Оператор while, или цикл while, повторяет строки кода, пока сохраняется истинность определенного условия. В листинге 3 показан пример сценария, в котором устанавливается переменная и выдается значение этой переменной при условии, что оно больше 0. Выходные данные сценария — числа 5, 4, 3, 2 и 1.

Код в скобках после ключевого слова while — условный оператор, который определяет, сколько раз выполняется код в фигурных скобках (известный как блок сценария, scriptblock). Когда вы используете цикл while, PowerShell проверяет условие в начале цикла. Выполните команду help about_While в PowerShell, чтобы получить больше информации и примеры цикла while.

Оператор Do

Оператор do, или цикл do, похож на оператор while; разница в том, что PowerShell проверяет условный оператор в конце цикла, а не в начале. Для цикла do требуется, чтобы в начале блока присутствовало ключевое слово while или until, поэтому мы обычно называем его циклом do while или do until. В листинге 4 показан тот же цикл, что и в листинге 3, реализованный в виде цикла do while.

В листинге 5 показан тот же цикл, что и в листингах 3 и 4, но реализованный в виде цикла do until. Ключевое слово until меняет логику цикла «повторять до тех пор, пока условие не станет истинным» вместо «повторять, пока условие истинно».

Единственная разница между циклами while, do while и do until — место проверки оператора условия (начало или конец цикла) и логика повторения (пока условие не нарушится или до его выполнения). Выполните команду help about_Do в PowerShell, чтобы получить больше информации и примеры циклов do while и do until.

Оператор For

Оператор for, или цикл for, повторяет код в блоке в зависимости от набора условий. Код в цикле for имеет инструкцию инициализации, инструкцию условия и инструкцию повторения. Инструкция инициализации выполняется в начале цикла и задает начальные условия, инструкция условия проверяет, должен ли продолжаться цикл, а инструкция повторения выполняется в каждом цикле. В листинге 6 показан простой пример цикла for.

В листинге 6 инструкция инициализации — $n = 5, инструкция условия — $n -ge 1, а инструкция повторения — $n-. Вывод листинга 6 точно такой же, как в листингах 3, 4 и 5. Выполните команду help about_For в PowerShell, чтобы получить больше информации и примеры цикла for.

Какой оператор использовать

Все четыре основных оператора итерации PowerShell (while, do while, do until и for) позволяют повторно выполнять код в зависимости от условия. Используйте тот оператор повторения, который позволяет получить более ясный программный код.

Оператор Foreach

Пользователям, более глубоко знающим PowerShell, известно об операторе foreach, или цикле foreach, который позволяет повторять команды для каждого элемента массива или коллекции объектов. Цикл foreach больше похож на команду For пакетного файла. В следующей статье я покажу, как можно заменить команду For пакетного файла в PowerShell.

Подпрограммы PowerShell

PowerShell не нуждается в команде Call или метках подпрограмм. Вместо этого в PowerShell применяются функции, как в других структурированных языках программирования. Функция — просто имя блока программного кода. Для запуска кода в функции просто вставьте имя функции в программу. В листинге 7 содержится простой пример как определения, так и выполнения функции PowerShell.

Ключевое слово function указывает PowerShell, что мы определяем функцию. Вставляя имя функции в программный код (как в последней строке листинга 7), PowerShell выполняет код внутри фигурных скобок.

Подпрограммы пакетного файла позволяют передавать параметры в подпрограмму с командой Call, и вы можете использовать подставляемые параметры в подпрограмме (%1 и т. д., как показано в листинге 2). Оператор param в верхней части функции позволяет сделать то же в PowerShell: он определяет параметры функции. Листинг 8 представляет собой расширенный вариант листинга 7 с параметром.

При выполнении программного кода в листинге 8 с параметром переменная $name в функции заменяется параметром, переданным из последней строки (строка «Ken»).

Напомню, что у подпрограмм пакетного файла нет собственного способа для возврата значений. Вывод функции в листинге 8 — собственно выходная строка. Кроме того, PowerShell без проблем возвращает несколько значений из функции; значения автоматически возвращаются списком (также именуемым массивом или коллекцией). В листинге 9 показана функция, которая возвращает список из трех чисел.

Таким образом, в PowerShell нет необходимости в командах Goto и Call. Циклические конструкции PowerShell (while, do while, do until и for) заменяют Goto, а функции заменяют команду Call. Если вы все еще создаете пакетные файлы, то эта статья поможет вам заменить команды Goto и Call в ваших будущих сценариях PowerShell.

Листинг 1. Пример пакетного файла Goto
@Echo Off
Set NUM=5
:REPEAT
Echo %NUM%
Set /A NUM-=1
If %NUM% GTR 0 Goto :REPEAT
Set NUM=
Листинг 2. Пакетный файл с подпрограммой
@Echo Off
Call :SAYHELLO Ken
Echo End of batch file
Goto :END
:SAYHELLO
Echo Hello, %1
:END
Листинг 3. Цикл while в PowerShell
$n = 5
while ( $n -gt 0 ) {
  $n
  $n--
}
Листинг 4. Цикл do while в PowerShell
$n = 5
do {
  $n
  $n--
} while ( $n -gt 0 )
Листинг 5. Цикл do until в PowerShell
$n = 5
do {
  $n
  $n--
} until ( $n -eq 0 )
Листинг 6. Цикл for в PowerShell
for ( $n = 5; $n -ge 1; $n-- ) {
  $n
}
Листинг 7. Простая функция PowerShell
function SayHello {
  "Hello, world"
}
# Run the function
SayHello
Листинг 8. Функция PowerShell с параметром
function SayHello {
  param($name)
  "Hello, $name"
}
# Run the function
SayHello Ken
Листинг 9. Функция PowerShell возвращает список
function MyFunction {
  $list = @(1,2,3)
  $list
}
$result = MyFunction
# Output the list
$result