我什么时候可以在我的 Powershell 命令中使用换行符(换行符)来提高可读性

When can I use newlines (line breaks) in my Powershell commands to improve readability

我如何知道何时可以在我的 Powershell 脚本中使用新 Lines/Carriage returns?搜索这个答案时的所有搜索结果都指向Output。在这种情况下,我不关心输出。我对自己格式化 Powershell 脚本以提高可读性的能力更感兴趣。

例如。下面是 Powershell 命令行的两个版本。一个有效,一个无效。在这种情况下,该命令的作用并不重要。关键是我需要知道什么时候可以创建新行,什么时候不能。

这个命令行可以工作,因为它只是一个很长的单行:

& 'C:\Program Files\ArangoDB3 3.3.3\usr\bin\arangoimp.exe' --file 'C:\Program Files\ArangoDB3 3.3.3\usr\bin\tstImportJSON.json' --type json --collection users --progress true --overwrite true --server.username root --server.password password

由于脚本中间有一个换行符,此命令行不起作用。

& 'C:\Program Files\ArangoDB3 3.3.3\usr\bin\arangoimp.exe' --file 
'C:\Program Files\ArangoDB3 3.3.3\usr\bin\tstImportJSON.json'
--type json --collection users --progress true --overwrite true
--server.username root --server.password password

在我的例子中,我只是 运行 添加换行符后同一命令行的不同版本,以查看它们是否有效。我知道我可以在使用 IF 语句时开始换行。我还可以在通过管道输送对象时使用换行符 |。我的假设是某个地方有一个 Powershell 脚本规则列表。当我最初开始接触 Powershell 时,我以为我曾在某个地方见过它们,但现在不知道它在哪里。

您可以使用`作为line-continuation字符[1] 在一行的最末端(后面甚至不允许有空格)以便将其分布在多行中。

这是一个简化的例子:

& cmd.exe /c echo `
 hi `
 there

这相当于 & cmd.exe /c echo hi there 并产生 hi there

注:

  • 由于 ` 字符在视觉上很微妙,而且不小心在其后放置字符很容易破坏语法,请考虑使用 数组 作为替代方案 - 见下文。

  • 单个命令必须在一行中,因此如果您想将它们分布在多行中,则需要 `,如上所示。

  • 但是,管道中,您可以用|结束行并继续下一行,不需要 `;例如:

    Get-Date | # Because the line ends with |, parsing continues on the next line.
      Select-Object Day
    
    • PowerShell [Core] v7+ 中,您也可以将 | 放在(非常) 的开头下一个行:

      Get-Date  # PS v7+ only
      | Select-Object Day
      
  • 另外,if individual arguments create a new parsing context in expression mode - 例如固有 multi-line 能力 (...) 表达式或脚本块 ({...}) 传递给 cmdlet - 您也可以自由地将表达式分布在多行中;例如:

    1, 2, 3 | ForEach-Object { # { starts a multiline-aware context
      $_ + 1
    }
    
  • 一个混合案例是一个array-literal 参数 ,它允许您 在内部元素的 , 分隔符 :

    之后中断命令
    Get-Date | Select-Object -Property Day,
                                       Year
    
  • start 在表达式模式下 always 允许跨多行传播的语句s(尽管 embedded command-mode 语句受到通常的限制):

    $foo =         # an assignment is parsed in expression mode
            'bar'  
    

或者,考虑使用数组[2]来传递参数,它允许您使用多行 expression-mode 语法将参数定义为单独的数组元素 beforehand:

# Construct the array of arguments (using multiline expression syntax)...
$arguments = '/c',
             'echo',
             'hi there'

# ... and pass it to cmd.exe
& cmd.exe $arguments 

注意:PowerShell 将数组元素 hi there 作为 "hi there" 传递:它使用自动 double-quoting 来确保参数被识别为 单个 目标程序的参数。


[1] ` 是 PowerShell 的 general-purpose 转义字符。放在一行的最后,它的功能略有不同:不是 转义 后面的换行符(这意味着 保留 它作为文字),它有效地告诉 PowerShell 删除 它并将下一行视为当前行的延续。

[2] 这个答案的早期形式推荐 array-based splatting, before PetSerAl 指出调用 外部程序 就足够了使用数组 as-is.
虽然也可以使用 splatting,但如果数组元素之一是 --%,stop-parsing 符号,其语义会略有不同(简而言之:只有当 splatting 时 --% 才有其特殊含义) .
Splatting 在调用 PowerShell 命令时是一种有用的技术,但是,主要以其 hash-table 形式(参见前面的 link) .

进一步分解脚本以提高可读性。

 = "--file 'C:\Program Files\ArangoDB3 3.3.3\usr\bin\tstImportJSON.json'"
 = "--type json"
 = "--collection users"
 = "--progress true"
 = "--overwrite true"
 = "--server.username root"
 = "--server.password password"
$Arguments = "      "
& 'C:\Program Files\ArangoDB3 3.3.3\usr\bin\arangoimp.exe' $Arguments

您的输出将如下所示。

C:\Program Files\ArangoDB3 3.3.3\usr\bin\arangoimp.exe --file 'C:\Program Files\ArangoDB3 3.3.3\usr\bin\tstImportJSON.json' --type json --collection users --progress true --overwrite true --server.username root --server.password password

通常情况下,我通常会将像这样看起来更丑陋的野兽移到它自己的功能中。

格式化 PowerShell 参数以提高可读性的标准方法是 splatting, which consists of assigning a hash table 到一个带有选项的命名 splatting 变量,并在需要时使用 At 符号取消引用参数。

您的 运行 带有参数的应用程序的具体示例将如下所示,在 idiomatic PowerShell.

$arangoImpOptions = @{
    FilePath = "$env:ProgramFiles\ArangoDB3 3.3.3\usr\bin\arangoimp.exe"
    Arguments = @{
        file = "$env:ProgramFiles\ArangoDB3 3.3.3\usr\bin\tstImportJSON.json"
        type = 'json'
        collection = 'users'
        progress = 'true'
        overwrite = 'true'
        'server.username' = 'root'
        'server.password' = 'password'
    }.GetEnumerator().ForEach({ '--{0} "{1}"' -f @($_.Key, $_.Value) }) -join ' '
}
Start-Process @arangoImpOptions