首页 > 解决方案 > 为什么 Range.BorderAround 会向控制台发出“True”?

问题描述

使用 BorderAround 会向控制台发出“True”。

$range = $sum_wksht.Range('B{0}:G{0}' -f ($crow))
$range.BorderAround(1, -4138)

这可以通过使用以下方法之一来克服。

$wasted = $range.BorderAround(1, -4138)
[void]$range.BorderAround(1, -4138)

为什么需要这个?我没有正确创建范围吗?有更好的解决方法吗?

标签: excelpowershelloutput

解决方案


为什么需要这个?

这是必需的,因为该BorderAround方法具有返回值,并且在 PowerShell 中,任何输出(返回)数据命令或表达式...都会隐式输出(成功)输出流,默认情况下会发送到主机,通常是控制台PowerShell 会话在其中运行的窗口(终端)。

也就是说,数据显示在控制台/终端中,除非是:

  • 捕获 ( $var = ...)
  • 通过管道发送以进行进一步处理(... | ...;最后一个管道段的命令可能会或可能不会自己产生输出)
  • 重定向 ( ... >)

或其任何组合。

那是:

$range.BorderAround(1, -4138)

是(更有效的)简写:

Write-Output $range.BorderAround(1, -4138)

Write-Output很少需要显式使用。)

由于您不想要该输出,因此您必须抑制,为此您有多种选择:

  • $null = ...

  • [void] (...)

  • ... > $null

  • ... | Out-Null

$null = ...可能是最好的整体选择,因为:

  • 它传达了预先压制的意图

    • 虽然也这样做,但出于句法原因[void] = (...),它通常需要您将表达式括起来;(...)例如,[void] 1 + 2不能按预期工作,仅[void] (1 + 2); 同样,命令必须始终包含在(...); [void] New-Item test.txt不起作用,只有[void] (New-Item test.txt)
  • 它在命令输出(例如,$null = Get-AdUser ...)和表达式输出(例如,$null = $range.BorderAround(1, -4138))方面表现良好。

相反,请避免... | Out-Null,因为它通常要慢得多(PowerShell (Core) 6+ 中无副作用表达式输出的边缘情况除外)[1]

但是,如果您需要使所有 输出流静音- 不仅是成功输出,还有错误、详细输出...... - 您必须使用*> $null


为什么 PowerShell 隐式产生输出?

  • 作为一个shellPowerShell 的输出行为是基于的,就像在传统的 shell(如cmd.exeBash 或 Bash)中一样。(虽然传统的 shell 有2 个输出流 - stdout 和 stderr - PowerShell 有6 个,以便提供更复杂的功能 - 请参阅about_Redirection。)

    • cmdlet、脚本或函数可以根据需要随时写入输出流,这样的输出通常可以立即显示,但也可以显示给潜在的消费者,这使得流水线提供的流式、一对一处理成为可能.

    • 这与传统的编程语言形成对比,后者的输出行为基于返回值,通常通过return关键字提供,它将输出数据(返回值)与流控制(退出范围并返回给调用者)混为一谈。

      • 一个常见的陷阱是期望 PowerShell 的return语句执行相同的操作,但事实并非如此:return <val>只是 的语法糖<val>; return,即隐式输出 of<val>后跟无条件将控制权返回给调用者;值得注意的是,使用return排除从相同范围内的早期语句生成输出。
  • 与传统的 shell 不同,PowerShell不需要显式的 write-to-the-output 流命令来生成输出

    • 虽然 PowerShell 确实有对应的echo,即Write-Output,但很少需要使用它。

      • 在极少数情况下Write-Output有用的是防止在输出上枚举集合-NoEnumerate,或者使用通用参数 -OutVariable来输出数据并将其捕获到变量中(通常只需要表达式,因为 cmdlet 和高级函数/脚本本身支持-OutVariable)。
    • 隐式输出行为:

      • 通常是一种祝福

        • 对于交互式实验 - 只需键入任何语句 - 特别包括诸如[IO.Path]::GetExtension('foo.txt')和之类的表达式[math]::Pow(2, 32)- 并查看其输出(类似于REPL的行为)。
        • 用于编写不需要说明隐含行为的简洁代码(参见下面的示例)。
      • 有时可能是一个陷阱

        • 适用于习惯于传统编程语言语义的用户。

        • 由于预期不会产生输出的语句可能会意外污染输出流,例如在您的情况下;一个更典型的例子是类的.Add()方法[System.Collections.ArrayList]意外产生输出。

例子:

# Define a function that takes an array of integers and
# outputs their hex representation (e.g., '0xa' for decimal 10)
function Get-HexNumber {
  param([int[]] $numbers)      
  foreach ($i in $numbers) {
    # Format the integer at hand 
    # *and implicitly output it*.
    '0x{0}' -f $i.ToString('x')
  }
}

# Call the function with integers 0 to 16 and loop over the
# results, sleeping 1 second between numbers.
Get-HexNumber (0..16) | ForEach-Object { "[$_]"; Start-Sleep 1 }

以上产生以下结果:

[0x0]
# 1-second pause
[0x1]
# 1-second pause
[0x2]
...
[0x10]

这演示了行为的流方面:Get-HexNumber的输出可用于ForEach-Objectcmdlet 调用,因为它正在生成,而不是 Get-HexNumber退出之后。


[1] 在 PowerShell (Core) 6+ 中,Out-Null如果前面唯一的管道段是无副作用的表达式而不是方法或命令调用,则进行优化;例如,1..1e6 | Out-Null几乎没有时间执行,因为表达式似乎甚至没有执行。但是,这样的场景是非典型的,功能等效 Write-Output (1..1e6) | Out-Null的运行需要很长时间,比$null = Write-Output (1..1e6).


推荐阅读