[英]What decides if a value is returned from a PowerShell function?
我试图弄清楚是什么决定了一个值是否从 PowerShell 函数返回,但我遇到了一些奇怪的问题。 about_return 文档说:
在 PowerShell 中,即使没有包含 Return 关键字的语句,每个语句的结果也会作为输出返回。
但这似乎掩盖了细节。 如果我运行这个:
function My-Function {
1
[System.Console]::WriteLine("Hello")
$null
$true
$false
0
2
}
运行它会返回一个数组(以及打印“Hello”):
1
True
False
0
2
这意味着$null
不会自动返回。 然后我尝试递增,因为我在函数中使用它:
function My-Function {
$n = 1
$n
$n++
($n++)
-join @(1, 2, 3)
(-join @(1, 2, 3))
}
返回:
1
2
123
123
所以, $n
和$n++
被返回了,但是($n++)
不是? 但是当与另一个运算符( -join
)相比时,在每种情况下都是相同的。 为什么$n++
周围的括号会阻止它被返回,为什么其他运算符的行为不一样? 这更令人困惑,因为=
运算符似乎以相反的方式工作:
function My-Function {
($n = 1)
$n
$n++
($n++)
}
返回:
1
1
2
现在包装赋值会导致它被返回,而包装$n++
导致它不被返回。
总之,我只想知道一种能够查看函数中的一行代码并确定它是否会导致返回值的直接方法。
本节讨论示例函数中的特定语句。
有关背景信息,请参阅底部部分。
$n = 1
和$n++
是赋值,因此不会产生输出。$n
是一个表达式,其值是输出$null
- 同上,但即使是output ,默认情况下也不显示($n++)
- 由于(...)
封闭 - 将赋值转换为表达式,因此确实输出了指定的值(也)。
(++$n)
[System.Console]::WriteLine("Hello")
直接打印到控制台,它绕过了PowerShell 的输出流系统。
PowerShell遵循传统 shell 的模型,围绕流组织- 有关 PowerShell 支持的所有 6 个流的概述,请参阅概念about_Redirection帮助主题。 [1]
也就是说,脚本或函数中的任何语句(因此可能是多个语句)都可以写入任何输出流。
主输出流,为了传达数据,是成功的输出流(其数目为1
),并且只有其通过发送管道默认,因此默认只有它在一个变量中被捕获,抑制,或重定向到一份文件。
有两种方法可以写入成功输出流,即产生数据输出:
明确地,使用Write-Output
调用 - 尽管很少需要。
通常是隐式的,既不捕获、抑制也不重定向语句产生的输出。
换句话说:默认情况下,任何命令(例如Get-ChildItem *.txt
)或表达式(例如1 + 2
)的输出都会发送到成功输出流。
不同于传统的编程语言, return
并不需要产生输出-事实上,其主要目的是通过独立于退出范围产生任何输出的封闭范围,但作为一个语法上的方便,你可以在这两个方面的结合:
return <command-or-expression>
实际上与以下两个语句相同,其中第一个(可能)产生输出,第二个退出作用域: <command-or-expression>; return
<command-or-expression>; return
至于分配- 例如$n = 1; $n += 1; ++$n; $n--
$n = 1; $n += 1; ++$n; $n--
$n = 1; $n += 1; ++$n; $n--
:
(...)
在分组操作; 例如($n = 1)
都将1
分配给变量$n
并输出1
,这允许它参与更大的表达式,例如($n = 1) -gt 0
至于输出枚举行为:
默认情况下, PowerShell本着流式输出的精神枚举正在输出的集合:也就是说,它将集合的元素一个一个地发送到管道。
在极少数情况下,您确实需要将集合作为一个整体输出 - 通常应该避免这种情况,以免混淆参与管道的其他命令,这些命令通常确实期望逐个对象输入 - 您有两个选择:
, $collection
(原文如此;使用辅助单元素包装器数组)Write-Output -NoEnumerate $collection
至于输出$null
:
$null
输出到管道,但默认情况下不显示。
$null
本身不产生可见输出,
但以下返回$true
,表明该值已发送:
$null | ForEach-Object { $null -eq $_ } # -> $true
请注意, PowerShell 还有一个“数组值$null
”值,用于表示命令缺少输出,技术上表示为[System.Management.Automation.Internal.AutomationNull]::Value
单例。 在表达式上下文中,此值被视为与$null
相同,但在管道中它的行为类似于没有元素的可枚举,因此不会通过管道发送任何内容- 有关更多信息,请参阅此答案。
至于抑制(丢弃)不需要的输出/重定向到文件:
抑制语句成功输出的最佳通用方法是分配给$null
( $null = ...
); 例如:
# .Add() outputs a value, which is usually unwanted. $null = ($list = [System.Collections.ArrayList]::new()).Add('hi')
注意:下面讨论输出抑制,通过$null
作为重定向目标,但类似地适用于将输出重定向到文件,通过指定文件名或路径作为目标。 [2]
要选择性地抑制不同的输出流,请在>$null
加上其编号; 例如3>$null
抑制警告流输出。
要抑制所有流的输出,在外部程序的情况下,它涵盖 stdout 和 stderr,请使用重定向*>$null
。
至于合并输出流:
1
)可以合并到.2>&1
和/或3>&1
),或合并所有(其他) : *>&1
2
)是[System.Management.Automation.ErrorRecord]
实例 - 有关更多信息,请参阅此答案。至于绕过PowerShell 的流系统:
Out-Host
和[Console]::WriteLine()
调用绕过PowerShell 的输出流并直接写入主机/控制台(终端)。 (主机是托管 PowerShell 引擎的任何环境,通常是但不一定是控制台(终端);其他主机的示例是PowerShell SDK和 PowerShell 远程处理中使用的主机)。
Write-Host
曾经无条件地绕过 PowerShell 的输出流,并且默认情况下仍然如此,但是 - 从 PowerShell 版本 5 - 现在将其输出发送到信息流(流号6
),在那里可以按需捕获/重定向 - 请参阅此答案想要查询更多的信息。
[1] 请注意,PowerShell 本身没有输入流的概念,因此也不支持 stdin 重定向运算符<
熟悉的其他 shell。 相反,命令通过管道接收流输入(仅)。 为了从外部世界接收数据,通过 PowerShell CLI的 stdin 流,必须使用自动$input
变量- 请参阅此答案。
[2] 使用>
(或>>
)重定向到文件在幕后有效地使用了Out-File
cmdlet,因此它的默认字符编码是Windows PowerShell 中的“Unicode”(UTF-16LE)和 BOM- PowerShell (Core) 7+ 中的UTF-8 更少。 但是,在 PowerShell 5.1 及更高版本中,您可以通过$PSDefaultParameterValues
首选项变量控制此编码 - 请参阅此答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.