【问题标题】:Powershell color formatting with format operator使用格式运算符的 Powershell 颜色格式化
【发布时间】:2020-02-03 10:53:18
【问题描述】:

我在脚本中使用格式运算符,示例如下:

$current = 1
$total   = 1250
$userCN  = "contoso.com/CONTOSO/Users/Adam Smith"

"{0, -35}: {1}" -f "SUCCESS: Updated user $current/$total", $userCN

这预计会显示以下输出:

SUCCESS: Updated user 1/1250 : contoso.com/CONTOSO/Users/Adam Smith

格式运算符用于将目标输出文本保留在适当的位置,当前/总运行数字在 1-99999 之间变化。如果没有格式运算符,我可以像这样突出显示成功线:

Write-Host -BackgroundColor Black -ForegroundColor Green "SUCCESS: Updated user $current/$total: $userCN"

但问题是如何将高亮颜色与格式运算符结合使用?只有-f 参数,它不允许使用颜色参数,因为首先它与Write-Host 不同。

【问题讨论】:

  • 把格式化的东西放在括号和像Write-Host ("{0, -35}: {1}" -f "SUCCESS: Updated user $current/$total", $userCN) -BackgroundColor Black -ForegroundColor Green这样的Write-Host之间
  • 似乎有效,谢谢!上面的文档也定义了要与美元符号一起使用的子表达式,但无论有没有它都可以使用。我想我会遵循规范并把 $ 放在适当的位置。
  • @JosefZ:我建议不要使用$(...) 来传递命令参数 - (...) 在绝大多数情况下就足够了,并且没有副作用;仅当您需要嵌入复合语句多个命令或表达式时,才使用$(...) / @(...)

标签: powershell syntax parameter-passing


【解决方案1】:

与其他 shell 不同,PowerShell 允许您将命令和表达式作为命令参数简单地通过将它们括在括号中,即通过使用(...)grouping operator

当调用 PowerShell 命令(cmdlet、脚本、函数)时,输出按原样作为参数传递,作为其原始输出类型。

因此,Theo的评论解决方案是正确的:

Write-Host -BackgroundColor Black -ForegroundColor Green `
           ("{0, -35}: {1}" -f "SUCCESS: Updated user $current/$total", $userCN) 

也就是说,(...) 中的 -f 表达式被执行,并且其输出(在这种情况下为单个字符串)作为位置参数传递给 Write-Host(隐式绑定到 -Object 参数)。


请注意,你确实不需要需要$(...)subexpression operator,在这种情况下:

(...) 足以包含表达式或命令。

事实上,在某些情况下,$(...) 可能会无意中修改您的论点,因为它的作用类似于管道;也就是说,它枚举和重建数组表达式作为常规 PowerShell 数组(可能会丢失强类型)并解包单元素数组

# Pass a single-element array to a script block (which acts like a function).
# (...) preserves the array as-is.
PS> & { param($array) $array.GetType().Name } -array ([array] 1)
Object[]  # OK - single-element array was passed as-is

# $(...) unwraps it.
PS> & { param($array) $array.GetType().Name } -array $([array] 1)
Int32  # !! Single-element array was unwrapped.

# Strongly-typed array example:
PS> & { param($array) $array.GetType().Name } ([int[]] (1..10))
Int32[] # OK - strongly typed array was passed as-is.

# Strongly-typed array example:
PS> & { param($array) $array.GetType().Name } $([int[]] (1..10))
Object[] # !! Array was *enumerated and *rebuilt* as regular PowerShell array.

$(...)主要用途是:

  • 扩展表达式或命令的输出expandable strings(字符串插值)

  • 发送复合语句输出,例如foreach (...) { ... }if (...) { ... }多个语句预先收集输出之后直接通过管道((...) 也是如此);但是,您也可以包装此类语句 & { ... }(或 . { ... } 以便直接在调用者的范围内而不是子范围内执行)以获得通常的 streaming 行为(逐个- 一个输出传递)在管道中。

    • 退后一步:鉴于您已经可以在变量赋值中使用复合语句作为表达式 - 例如,$evenNums = foreach ($num in 1..3) { $num * 2 } - 和表达式一般 em> 被接受为管道的第一段——例如,'hi' | Write-Host -Fore Yellow——令人惊讶的是,它目前不适用于复合语句; this GitHub issue 询问是否可以取消此限制。

在将参数传递给命令的上下文中:

  • 使用$(...)subexpression operator 仅当您想传递多个命令或(一个或多个)命令的输出复合语句作为参数和/或,如果输出恰好是一个单个对象,您希望该对象按原样使用或者,如果它恰好是一个单元素数组(可枚举),您希望它是unwrapped(传递元素本身,而不是数组。

    • 当然,如果您正在构造一个 string 参数,$(...) 可以在该字符串中用于字符串插值 - 例如,Write-Host "1 + 1 = $(1 + 1)"
  • 使用@(...)array subexpression operator 仅当您想将多个命令的输出作为参数传递和/或你想确保输出变成一个数组;也就是说,输出作为[object[]] 类型的(常规 PowerShell)数组返回,即使它恰好包含 one 对象。从某种意义上说,这是$(...)在单对象输出情况下的行为的:它确保单对象输出也变成一个数组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多