Почему мне нужно сначала написать свои функции в моем скрипте PowerShell? - PullRequest
41 голосов
/ 12 октября 2010

У меня есть скрипт, который я использую функции для переноса частей кода, которые позволяют мне перемещаться по разделам в указанной точке.Что я обнаружил, так это то, что для правильной работы мне нужно, чтобы в скрипте были перечислены первые функции.

Неработающий пример

$stepChoice = read-host 'Where would you like to start.'

switch($stepChoice)
{
    1{Step1}
    2{Step2}
    3{Step3}

}

# Steps.ps1 
function Step1 { 
    'Step 1' 
    Step2 
} 
function Step2 { 
    'Step 2' 
    Step3 
} 
function Step3 { 
    'Step 3' 
    'Done!' 
}

Ошибка

ЭтоДайте мне следующую ошибку:

Термин «Шаг1» не распознается как имя командлета, функции, файла сценария или работоспособной программы.Проверьте правильность написания имени или, если путь был указан, проверьте правильность пути и повторите попытку.

 At C:\Tools\Scripts\functiontest.ps1:7 char:12
  +     1{Step1 <<<< }
  + CategoryInfo          : ObjectNotFound: (Step1:String) [], CommandNotFoundException
  + FullyQualifiedErrorId : CommandNotFoundException*

Рабочий пример

Если изменить порядок вокруг, он работает нормально:

# Steps.ps1 
function Step1 { 
    'Step 1' 
    Step2 
} 
function Step2 { 
    'Step 2' 
    Step3 
} 
function Step3 { 
    'Step 3' 
    'Done!' 
}

#steps
$stepChoice = read-host 'Where would you like to start.'

switch($stepChoice)
{
    1{Step1}
    2{Step2}
    3{Step3}

}

Почему?

Я предполагаюэто потому, что PS не загружает функции.

Почему это так и есть ли лучший способ выложить эту структуру кода?

Ответы [ 5 ]

55 голосов
/ 13 октября 2010

Помните, что вообще то, что работает в скрипте, должно работать в командной строке .

Это не было правдой в CMD. GOTO и FOR %I IN (...) DO %%I являются двумя примерами.

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

Кроме того, я могу взять скрипт, который работает некорректно, вставить его в интерактивную оболочку и изучить полученное состояние.

В интерактивной командной строке вы никак не могли бы написать это:

F
function F { "Hello, World!" }

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

function Main 
{
    F
}

function F
{
    "Hello, World!"
}

Main
33 голосов
/ 13 октября 2010

Изменение порядка сценариев

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

Следовательно, в этом случае вы должны переместить определения функции до *Оператор 1005 * - как вы обнаружили.

Форвардные объявления

Даже некоторые скомпилированные языки ведут себя так, особенно C / C ++, и требуют форвардных объявлений для работывокруг этого вопроса.

Другие скомпилированные языки, такие как C #, делают несколько проходов по коду во время компиляции, так что предварительные объявления не требуются.

11 голосов
/ 02 апреля 2015

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

Steps-Lib.ps1

# Since this is just function definitions it is safe to source
function Step1 { 
    'Step 1' 
    Step2 
} 
function Step2 { 
    'Step 2' 
    Step3 
} 
function Step3 { 
    'Step 3' 
    'Done!' 
}

Steps.ps1

# This sources the Steps-Lib.ps1 so that the functions are available
. "./Steps-Lib.ps1"

$stepChoice = read-host 'Where would you like to start.'

switch($stepChoice)
{
    1{Step1}
    2{Step2}
    3{Step3}
}
4 голосов
/ 13 октября 2010

В дополнение к тому, что сказал Кит о заказе переводчика, он также является частью дизайна Powershell. Он действительно должен вести себя как интерфейс к объектам CLR и даже своим собственным командлетам. Таким образом, в «сценариях» PowerShell вы меньше создаете этот чрезвычайно сложный список действий и больше собираете набор других, меньших кусочков логики и определяете, как с ними взаимодействовать.

Не вдаваясь в квази-религиозную дискуссию о Powershell и ООП, самый простой способ выполнить то, что вы хотите, - это похоронить все ваши функции в отдельном файле (назовите его functions.ps1), а затем включить его в начале.

Итак, при условии, что все было в functions1.ps1

сделать

$functions = "$($MyInvocation.MyCommand.path | split-path)\functions.ps1"
. $functions

тогда

switch($stepChoice)
{
    1{Step1}
    2{Step2}
    3{Step3}

}

Будет работать просто отлично

0 голосов
/ 25 апреля 2019

Решение из блога Microsoft, заключить основной код в блок и позвонить в конце,

$MainFunction={
   $stepChoice = read-host 'Where would you like to start.'
   switch($stepChoice)
   {
       1{Step1}
       2{Step2}
       3{Step3}
   }
}
# Steps.ps1 
function Step1 { 
  'Step 1' 
   Step2 
} 
function Step2 { 
  'Step 2' 
   Step3 
} 
function Step3 { 
  'Step 3' 
  'Done!' 
}
#This line executes the program
& $MainFunction
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...