繁体   English   中英

什么决定是否从 PowerShell 函数返回值?

[英]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 内部捕获或重定向此类输出(请参阅下一节)。

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

  • 默认情况下,它们产生输出
  • 然而,作为一个选择,你可以让它们通过值(S)通过经分配(...)分组操作; 例如($n = 1)都将1分配给变量$n输出1 ,这允许它参与更大的表达式,例如($n = 1) -gt 0
    • 请注意,相关的$(...)子表达式运算符)和@(...)数组子表达式运算符没有这种效果——它们包装了一个或多个完整的语句,而不影响封闭的语句'内在输出行为; 例如$($n = 1)产生输出,因为$n = 1由本身不产生输出; 然而, $(($n = 1))确实如此,因为($n = 1)本身确实如此。

至于输出枚举行为

  • 默认情况下, 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 远程处理中使用的主机)。

    • 因此,无法从 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM