Powershell:来自函数的意外 return 值,使用 $args 访问参数
Powershell: unexpected return value from function, use of $args to access parameters
好的,我已经用不同的语言编写了很长一段时间,但我没有得到函数的 Powershells 概念 return?....
我是 Powershell 的新手,所以我确信我遗漏了一些非常基本的东西。
我有以下功能:
function plGetKeyValue ([string] $FileName, [string] $SectionName, [string] $Key)
{
if ($PSBoundParameters.Count -lt 2 -or $PSBoundParameters.Count -gt 3 )
{
"Invalid call to {0} in {1}" -f $MyInvocation.MyCommand.Name,
$MyInvocation.MyCommand.ModuleName
return
}
# Declaration
$lFileContents = ""
$lSections = ""
$lDataStart = ""
$lStart = -1
$lEnd = -1
$lFoundSection = ""
$lNextSection = ""
$lResults = ""
$lRetValue = ""
# Handle the optional parameter.
if ( $PSBoundParameters.Count -eq 2 ) {
$PSBoundParameters.Add('Key', $SectionName)
$PSBoundParameters.Remove('SectionName')
$Key = $SectionName
$SectionName = $null
}
# Read the file in
$lFileContents = Get-Content $FileName | Select-String -Pattern .*
# Get the sections.
$lSections = $lFileContents -match '\['
$lSections = $lSections -notmatch '#'
# Start of the data.
$lDataStart = $lFileContents | Select-String -Pattern "^#", "^$" -NotMatch `
| select-object -First 1
# We have a section.
if ( $PSBoundParameters.ContainsKey( 'SectionName' ) ) {
# Find the section.
$lFoundSection = $lSections | Select-String -Pattern "$lSectionName\b"
# If none found we are out.
if ( -Not $lFoundSection) { return $lRetValue }
# Starting point for the key search is the line following
# the found section.
$lStart = $lFoundSection[0].LineNumber
# Loop through the sections and find the one after the found one.
$lNextSection = $lSections | ForEach-Object {
# If we hit it, break.
if ($_.LineNumber -gt $lStart) {
break;
}
}
# Set the ending line for the search to the end of the section
# or end of file. Which ever we have.
if ($lNextSection) {
$lEnd = $lNextSection[0].LineNumber
} else {
$lEnd = $lFileContents[-1]
}
} else {
# No section.
$lStart = $lDataStart.LineNumber
# Set the ending line for the search to the end of the section
# or end of file. Which ever we have.
if ($lSections) {
$lEnd = $lSections[0].LineNumber
} else {
$lEnd = $lFileContents[-1]
}
}
# Extract the lines starting with the key.
$lResults = $lFileContents[$lStart..$lEnd] -match "$Key\b"
# We got results.
# Split the value off.
return $lRetValue = $lResults[0] | Select -ExpandProperty "Line"
}
创建此函数的过程引发了几个我研究过并感到困惑的问题
1) 文档指出应该使用 $args 来确定参数。它似乎永远不会为我填充?我正在使用版本 4?作为替代方案,我使用了 $PSBoundParameters。这是否可取?
2) 基于大量阅读和挠头,我发现 return 函数的值 rturn 所有未捕获的输出到管道。有人可以澄清未捕获的吗?
例如,我希望下面的函数return 变量$lRetValue 中的一个字符串。目前,它是 returning True。基于此,我相信我有一些未捕获的东西?但是我正在执行的所有内容都被捕获在一个变量中。我错过了什么?
调用例程正在调用以下形式的代码:
$FileName = "S:\PS\Home\GlobalConfig\jobs.cfg"
$key = "Help"
$section = "Section"
$r = plGetKeyValue $FileName $Key
write-host "r is: $r"
输出结果如下:
PS C:> S:\PS\Home\Job\Test.ps1
r 是:真
如有任何帮助,我们将不胜感激。
术语说明:有些武断,下面我会区分参数和参数:
- 参数作为定义为函数声明一部分的占位符,
- 与 arguments 不同,因为 values 绑定到给定调用中的占位符。
概念信息:
1) The documentation indicates that $args should be used to determine arguments.
$args
是一种 后备 机制,用于在 非高级 [=151] 中检查 未绑定 参数=](非 cmdlet)函数。
$args
已填充:
仅当您的函数不是一个高级函数(函数被标记为高级函数存在 param(...)
参数声明语句 - 与在 function someFunc(...)
中声明参数相反) - 如果装饰有 [CmdletBinding()]
属性 ).
即便如此,它也仅包含 未绑定 参数(未映射到声明参数的参数)。
换句话说:只有当你声明你的函数时根本没有任何参数时,$args
才包含 所有 个传递的参数。
相反,在高级函数中不能是未绑定参数,并使用无法绑定的参数调用高级函数参数简单地失败(产生错误)。
由于定义 高级 函数通常是可取的,因为它们最好与 PowerShell 基础结构作为一个整体集成,所以最好完全不使用 $args
。
相反,使用多个 parameter sets and/or 数组参数的组合来覆盖所有可能的有效输入参数场景。
$PSBoundArguments
包含绑定到 声明的 参数的参数,并且通常 不需要 ,因为对应于可以直接使用参数名称(例如 $SectionName
)。 (它有特殊用途,例如通过 splat @PSBoundArguments
将所有绑定参数传递给另一个 cmdlet/function)。
2) Based on a lot of reading and head scratching, I have found that return values from functions return all uncaptured output to the pipeline. Can someone, please clarify "uncaptured"?
通常,任何生成输出的 PowerShell 语句或表达式都会发送到 成功流(大致相当于 Unix shell 中的 stdout
) default,除非输出是 captured(例如,通过分配给变量)或 redirected(例如,通过将输出发送到文件)。
因此,与大多数编程语言的行为相反,如果您不希望语句产生输出,则必须采取行动。
如果您对语句的输出不感兴趣(而不是捕获/重定向它供以后使用),您可以重定向到 $null
(等效/dev/null
),管道到 cmdlet Out-Null
,或分配给虚拟变量 $null
($null = ...
).
因此,从某种意义上说,您可以调用 是 发送到成功流的输出 uncaptured.
然而,这与 return
声明无关:
return
语句 与 的工作方式与其他语言相同;它在 PowerShell 中的主要目的是作为 control-flow 机制 - 退出函数或脚本块 - 而不是 output 数据(甚至虽然它可以也用于此:带有一个参数,是另一种将输出发送到成功流的方法。
正在诊断您的具体问题:
有很多方法可以使您的函数成为更好的 PowerShell 公民[1]
,但您的直接问题是:
$PSBoundParameters.Remove('SectionName')
returns 布尔值 发送到输出流,因为您既不抑制、捕获也不重定向它.在你的例子中,由于 $SectionName
参数 是 绑定的,它确实在 $PSBoundParameters
中有一个条目,所以 $PSBoundParameters.Remove('SectionName')
returns $true
.
要抑制这种不需要的输出,请使用如下内容:
$null = $PSBoundParameters.Remove('SectionName')
一般来说,除非你知道一条语句不会产生输出,否则最好是安全地在前面添加$null =
(或使用等效的机制来抑制输出).
尤其是直接 方法 调用对象时,通常不清楚是否会返回一个值 - 变成输出(发送到成功流)。
[1] 以下帮助主题提供了更多信息:
- 参数的使用,包括如何使用 help -Full / -Detailed ...
:
检查它们
help about_Parameters
- 定义简单函数及其参数:
help about_functions
,
从中您可以进步到 高级 功能:
help about_functions_advanced
及其参数定义:
help about_Functions_Advanced_Parameters
好的,我已经用不同的语言编写了很长一段时间,但我没有得到函数的 Powershells 概念 return?....
我是 Powershell 的新手,所以我确信我遗漏了一些非常基本的东西。
我有以下功能:
function plGetKeyValue ([string] $FileName, [string] $SectionName, [string] $Key)
{
if ($PSBoundParameters.Count -lt 2 -or $PSBoundParameters.Count -gt 3 )
{
"Invalid call to {0} in {1}" -f $MyInvocation.MyCommand.Name,
$MyInvocation.MyCommand.ModuleName
return
}
# Declaration
$lFileContents = ""
$lSections = ""
$lDataStart = ""
$lStart = -1
$lEnd = -1
$lFoundSection = ""
$lNextSection = ""
$lResults = ""
$lRetValue = ""
# Handle the optional parameter.
if ( $PSBoundParameters.Count -eq 2 ) {
$PSBoundParameters.Add('Key', $SectionName)
$PSBoundParameters.Remove('SectionName')
$Key = $SectionName
$SectionName = $null
}
# Read the file in
$lFileContents = Get-Content $FileName | Select-String -Pattern .*
# Get the sections.
$lSections = $lFileContents -match '\['
$lSections = $lSections -notmatch '#'
# Start of the data.
$lDataStart = $lFileContents | Select-String -Pattern "^#", "^$" -NotMatch `
| select-object -First 1
# We have a section.
if ( $PSBoundParameters.ContainsKey( 'SectionName' ) ) {
# Find the section.
$lFoundSection = $lSections | Select-String -Pattern "$lSectionName\b"
# If none found we are out.
if ( -Not $lFoundSection) { return $lRetValue }
# Starting point for the key search is the line following
# the found section.
$lStart = $lFoundSection[0].LineNumber
# Loop through the sections and find the one after the found one.
$lNextSection = $lSections | ForEach-Object {
# If we hit it, break.
if ($_.LineNumber -gt $lStart) {
break;
}
}
# Set the ending line for the search to the end of the section
# or end of file. Which ever we have.
if ($lNextSection) {
$lEnd = $lNextSection[0].LineNumber
} else {
$lEnd = $lFileContents[-1]
}
} else {
# No section.
$lStart = $lDataStart.LineNumber
# Set the ending line for the search to the end of the section
# or end of file. Which ever we have.
if ($lSections) {
$lEnd = $lSections[0].LineNumber
} else {
$lEnd = $lFileContents[-1]
}
}
# Extract the lines starting with the key.
$lResults = $lFileContents[$lStart..$lEnd] -match "$Key\b"
# We got results.
# Split the value off.
return $lRetValue = $lResults[0] | Select -ExpandProperty "Line"
}
创建此函数的过程引发了几个我研究过并感到困惑的问题
1) 文档指出应该使用 $args 来确定参数。它似乎永远不会为我填充?我正在使用版本 4?作为替代方案,我使用了 $PSBoundParameters。这是否可取?
2) 基于大量阅读和挠头,我发现 return 函数的值 rturn 所有未捕获的输出到管道。有人可以澄清未捕获的吗?
例如,我希望下面的函数return 变量$lRetValue 中的一个字符串。目前,它是 returning True。基于此,我相信我有一些未捕获的东西?但是我正在执行的所有内容都被捕获在一个变量中。我错过了什么?
调用例程正在调用以下形式的代码:
$FileName = "S:\PS\Home\GlobalConfig\jobs.cfg"
$key = "Help"
$section = "Section"
$r = plGetKeyValue $FileName $Key
write-host "r is: $r"
输出结果如下:
PS C:> S:\PS\Home\Job\Test.ps1 r 是:真
如有任何帮助,我们将不胜感激。
术语说明:有些武断,下面我会区分参数和参数:
- 参数作为定义为函数声明一部分的占位符,
- 与 arguments 不同,因为 values 绑定到给定调用中的占位符。
概念信息:
1) The documentation indicates that $args should be used to determine arguments.
$args
是一种 后备 机制,用于在 非高级 [=151] 中检查 未绑定 参数=](非 cmdlet)函数。
$args
已填充:
仅当您的函数不是一个高级函数(函数被标记为高级函数存在
param(...)
参数声明语句 - 与在function someFunc(...)
中声明参数相反) - 如果装饰有[CmdletBinding()]
属性 ).即便如此,它也仅包含 未绑定 参数(未映射到声明参数的参数)。
换句话说:只有当你声明你的函数时根本没有任何参数时,$args
才包含 所有 个传递的参数。
相反,在高级函数中不能是未绑定参数,并使用无法绑定的参数调用高级函数参数简单地失败(产生错误)。
由于定义 高级 函数通常是可取的,因为它们最好与 PowerShell 基础结构作为一个整体集成,所以最好完全不使用 $args
。
相反,使用多个 parameter sets and/or 数组参数的组合来覆盖所有可能的有效输入参数场景。
$PSBoundArguments
包含绑定到 声明的 参数的参数,并且通常 不需要 ,因为对应于可以直接使用参数名称(例如 $SectionName
)。 (它有特殊用途,例如通过 splat @PSBoundArguments
将所有绑定参数传递给另一个 cmdlet/function)。
2) Based on a lot of reading and head scratching, I have found that return values from functions return all uncaptured output to the pipeline. Can someone, please clarify "uncaptured"?
通常,任何生成输出的 PowerShell 语句或表达式都会发送到 成功流(大致相当于 Unix shell 中的 stdout
) default,除非输出是 captured(例如,通过分配给变量)或 redirected(例如,通过将输出发送到文件)。
因此,与大多数编程语言的行为相反,如果您不希望语句产生输出,则必须采取行动。
如果您对语句的输出不感兴趣(而不是捕获/重定向它供以后使用),您可以重定向到 $null
(等效/dev/null
),管道到 cmdlet Out-Null
,或分配给虚拟变量 $null
($null = ...
).
因此,从某种意义上说,您可以调用 是 发送到成功流的输出 uncaptured.
然而,这与 return
声明无关:
return
语句 与 的工作方式与其他语言相同;它在 PowerShell 中的主要目的是作为 control-flow 机制 - 退出函数或脚本块 - 而不是 output 数据(甚至虽然它可以也用于此:带有一个参数,是另一种将输出发送到成功流的方法。
正在诊断您的具体问题:
有很多方法可以使您的函数成为更好的 PowerShell 公民[1] ,但您的直接问题是:
$PSBoundParameters.Remove('SectionName')
returns 布尔值 发送到输出流,因为您既不抑制、捕获也不重定向它.在你的例子中,由于 $SectionName
参数 是 绑定的,它确实在 $PSBoundParameters
中有一个条目,所以 $PSBoundParameters.Remove('SectionName')
returns $true
.
要抑制这种不需要的输出,请使用如下内容:
$null = $PSBoundParameters.Remove('SectionName')
一般来说,除非你知道一条语句不会产生输出,否则最好是安全地在前面添加$null =
(或使用等效的机制来抑制输出).
尤其是直接 方法 调用对象时,通常不清楚是否会返回一个值 - 变成输出(发送到成功流)。
[1] 以下帮助主题提供了更多信息:
- 参数的使用,包括如何使用 help -Full / -Detailed ...
:
检查它们
help about_Parameters
- 定义简单函数及其参数:
help about_functions
,
从中您可以进步到 高级 功能:
help about_functions_advanced
及其参数定义:
help about_Functions_Advanced_Parameters