为什么我需要先在PowerShell脚本中编写函数?

Dan*_*ell 46 powershell coding-style

我有一个脚本,我利用函数来包装部分代码,允许我在指定的点移动部分.我发现我必须在脚本中首先列出函数才能正确运行.

非工作的例子

$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!' 
}
Run Code Online (Sandbox Code Playgroud)

错误

这给我以下错误:

术语"Step1"未被识别为cmdlet,函数,脚本文件或可操作程序的名称.检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试.

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

工作实例

如果我改变它的顺序它工作正常:

# 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}

}
Run Code Online (Sandbox Code Playgroud)

为什么?

我猜这是因为PS没有加载这些功能.

为什么这样,有没有更好的方法来布局这个代码结构?

Jay*_*uzi 56

请记住,通常,脚本中的工作应该在命令行中起作用.

在CMD中并非如此.GOTO并且FOR %I IN (...) DO %%I是两个例子.

在PowerShell中,我可以在命令行运行命令,直到得到我想要的结果,然后将历史记录粘贴到脚本中,然后编辑掉多余的位.

此外,我可以使用无法正常工作的脚本,将其粘贴到交互式shell中,并研究生成的状态.

在交互式命令行中,你无法写出这个:

F
function F { "Hello, World!" }

但是,在阅读脚本时,我想首先阅读顶级代码,然后在向下滚动时查看更多详细信息.一种方法是:

function Main 
{
    F
}

function F
{
    "Hello, World!"
}

Main

  • 这也是我解决此问题的首选方法,因为您可以轻松保持自上而下的可读性。 (2认同)

Kei*_*ill 39

重新排序脚本

PowerShell是一个脚本,而不是一个编译语言.因此,它逐行遍历脚本,从上到下,(在标记脚本之后)并沿途评估每个命令.如果还没有得到函数的定义并且您已经尝试调用该函数,PowerShell将抛出错误.

因此,在这种情况下,您必须在switch语句之前移动函数定义- 正如您所发现的那样.

前瞻性声明

甚至一些编译语言也是这样的,最着名的是C/C++,并且需要前向声明才能解决这个问题.

其他编译语言(如C#)在编译期间对代码进行多次传递,因此不需要前向声明.

  • 严格来说,这并不是因为它是一种脚本语言,而是因为这就是 PowerShell 解释代码的方式。JavaScript 也是一种脚本语言,但它具有函数提升功能,可以在作用域中执行代码之前查找函数定义并定义它们。这意味着您可以在定义的地方调用上面的函数。 (15认同)
  • perl 还可以在末尾定义函数 (2认同)

Sim*_*her 12

您还可以从单独的文件中获取函数定义:

步骤,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!' 
}
Run Code Online (Sandbox Code Playgroud)

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}
}
Run Code Online (Sandbox Code Playgroud)

  • 这将一直有效,直到您尝试从与它所在的文件夹不同的文件夹运行主脚本。为了使其更健壮,您需要将 `.. "$PSScriptRoot/Steps-Lib.ps1"` (2认同)

Cod*_*ack 8

微软博客的一个解决方案,将主要代码封装在一个块中,最后调用,

$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
Run Code Online (Sandbox Code Playgroud)