PowerShell的推荐编码风格是什么?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PowerShell的推荐编码风格是什么?相关的知识,希望对你有一定的参考价值。

如何编写PowerShell脚本是否有任何推荐的编码风格?

它不是关于如何构造代码(有多少函数,如果使用模块,......)。它是关于“如何编写代码以使其可读”。

在编程语言中有一些推荐的编码样式(缩进的内容,如何缩进 - 空格/制表符,在哪里创建新行,在哪里放括号,...),但我还没有看到任何关于PowerShell的建议。

我特别感兴趣的是:


如何写参数

function New-XYZItem
  ( [string] $ItemName
  , [scriptblock] $definition
  ) { ...

(我看到它更像'V1'语法)

要么

function New-PSClass  {
  param([string] $ClassName
       ,[scriptblock] $definition
  )...

或(为什么要添加空属性?)

function New-PSClass  {
  param([Parameter()][string] $ClassName
       ,[Parameter()][scriptblock] $definition
  )...

或(我在Jaykul的代码中看到的其他格式)

function New-PSClass {
  param(
        [Parameter()]
        [string]
        $ClassName
        ,
        [Parameter()]
        [scriptblock]
        $definition
  )...

要么 ...?


如何编写复杂的管道

Get-SomeData -param1 abc -param2 xyz | % {
    $temp1 = $_
    1..100 | % {
      Process-somehow $temp1 $_
    }
  } | % {
    Process-Again $_
  } |
  Sort-Object -desc

或(新行上的cmdlet名称)

Get-SomeData -param1 abc -param2 xyz |
  % {
    $temp1 = $_
    1..100 |
      % {
        Process-somehow $temp1 $_
      }
  } |
  % {
    Process-Again $_
  } |
  Sort-Object -desc |

如果有qazxsw poi,qazxsw poi和qazxsw poi参数怎么办?如何使其最具可读性?

-begin

要么

-process

缩进在这里很重要,并且在新行上也放置了什么元素。


我只是经常提到我脑海中浮现的问题。还有其他一些,但我想保持这个Stack Overflow问题“简短”。

欢迎任何其他建议。

答案

花了几年时间深入了解PowerShell v2.0后,我已经解决了这个问题:

-end

Stack Overflow的语法高亮显示器完全放弃了我。将其粘贴到ISE中。

另一答案

我相信PowerShell最全面的编码风格资源仍然是Get-SomeData -param1 abc -param2 xyz | % -begin { init } -process { Process-somehow2 ... } -end { Process-somehow3 ... } | % -begin { } ....

从他们的介绍:

与英语拼写和语法规则一样,PowerShell编程最佳实践和样式规则几乎总是有例外,但我们正在记录代码结构,命令设计,编程,格式化甚至样式的基线,这将帮助您避免常见问题,并帮助你编写了更多可重用,可读的代码 - 因为不需要重写可重用代码,并且可以维护可读代码。

他们还提供了这些Get-SomeData -param1 abc -param2 xyz | % ` -begin { init } ` -process { Process-somehow2 ... } ` -end { Process-somehow3 ... } | % -begin { } .... 链接:

  • <# .SYNOPSIS Cmdlet help is awesome. Autogenerate via a template so I never forget. .DESCRIPTION .PARAMETER .PARAMETER .INPUTS .OUTPUTS .EXAMPLE .EXAMPLE .LINK #> function Get-Widget { [CmdletBinding()] param ( # Think about which parameters users might loop over. If there is a clear # favorite (80/20 rule), make it ValueFromPipeline and name it InputObject. [parameter(ValueFromPipeline=$True)] [alias("Server")] [string]$InputObject, # All other loop candidates are marked pipeline-able by property name. Use Aliases to ensure the most # common objects users want to feed in will "just work". [parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$True)] [alias("FullName")] [alias("Path")] [string[]]$Name, # Provide and document defaults for optional parameters whenever possible. [parameter(Position=1)] [int]$Minimum = 0, [parameter(Position=2)] [int]$ComputerName = "localhost", # Stick to standardized parameter names when possible. *Especially* with switches. Use Aliases to support # domain-specific terminology and/or when you want to expose the parameter name of the .Net API you're wrapping. [parameter()] [Alias("IncludeFlibbles")] [switch]$All, ) # The three main function blocks use this format if & only if they are short one-liners begin { $buf = new-list string } # Otherwise they use spacing comparable to a C# method process { # Likewise, control flow statements have a special style for one-liners try { # Side Note: internal variables (which may be inherited from a parent scope) # are lowerCamelCase. Direct parameters are UpperCamelCase. if ($All) { $flibbles = $Name | Get-Flibble } elseif ($Minimum -eq 0) { $flibbles = @() } else { return } $path = $Name | ? { $_.Length -gt $Minimum } | % { $InputObject.InvokeGetAPI($_, $flibbles) } | ConvertTo-FullPath } finally { Cleanup } # In general, though, control flow statements also stick to the C# style guidelines while($true) { Do-Something if ($true) { try { Do-Something Do-Something $buf.Add("abc") } catch { Do-Something Do-Something } } } } } <# Pipelines are a form of control flow, of course, and in my opinion the most important. Let's go into more detail. I find my code looks more consistent when I use the pipeline to nudge all of PowerShell's supported language constructs (within reason) toward an "infix" style, regardless of their legacy origin. At the same time, I get really strict about avoiding complexity within each line. My style encourages a long, consistent "flow" of command-to-command-to-command, so we can ensure ample whitespace while remaining quite compact for a .NET language. Note - from here on out I use aliases for the most common pipeline-aware cmdlets in my stable of tools. Quick extract from my "meta-script" module definition: sal ?? Invoke-Coalescing sal ?: Invoke-Ternary sal im Invoke-Method sal gpv Get-PropertyValue sal spv Set-PropertyValue sal tp Test-Path2 sal so Select-Object2 sal eo Expand-Object % and ? are your familiar friends. Anything else that begins with a ? is a pseudo-infix operator autogenerated from the Posh syntax reference. #> function PipelineExamples { # Only the very simplest pipes get to be one-liners: $profileInfo = dir $profile | so @{Path="fullname"; KBs={$_.length/1kb}} $notNull = $someString | ?? "" $type = $InputObject -is [Type] | ?: $InputObject $InputObject.GetType() $ComObject | spv Enabled $true $foo | im PrivateAPI($param1, $param2) if ($path | tp -Unc) { Do-Something } # Any time the LHS is a collection (i.e. we're going to loop), the pipe character ends the line, even # when the expression looks simple. $verySlowConcat = "" $buf | % { $verySlowConcat += $_ } # Always put a comment on pipelines that have uncaptured output [destined for the caller's pipeline] $buf | ? { $_ -like "*a*" } # Multi-line blocks inside a pipeline: $orders | ? { $_.SaleDate -gt $thisQuarter -and ($_ | Get-Customer | Test-Profitable) -and $_.TastesGreat -and $_.LessFilling } | so Widgets | % { if ($ReviewCompetition) { $otherFirms | Get-Factory | Get-ManufactureHistory -Filter $_ | so HistoryEntry.Items.Widgets } else { $_ } } | Publish-WidgetReport -Format html # Mix COM, reflection, native commands, etc. seamlessly $flibble = Get-WmiObject SomethingReallyOpaque | spv AuthFlags 0xf -PassThru | im Put() -PassThru | gpv Flibbles | select -first 1 # The coalescing operator is particularly well suited to this sort of thing $initializeMe = $OptionalParam | ?? $MandatoryParam.PropertyThatMightBeNullOrEmpty | ?? { pwd | Get-Something -Mode Expensive } | ?? { throw "Unable to determine your blahblah" } $uncFolderPath = $someInput | Convert-Path -ea 0 | ?? $fallback { tp -Unc -Folder } # String manipulation $myName = "First{0} Last{1} " | ?+ "Suffix{2}" | ?replace "{", ": {" | ?f {eo richard berg jr | im ToUpper} # Math algorithms written in this style start to approach the elegance of functional languages $weightedAvg = $values | Linq-Zip $weights {$args[0] * $args[1]} | Linq-Sum | ?/ ($weights | Linq-Sum) } # Don't be afraid to define helper functions. Thanks to the script:Name syntax, you don't have to cram them into # the begin{} block or anything like that. Name, parameters, etc don't always need to follow the cmdlet guidelines. # Note that variables from outer scopes are automatically available. (even if we're in another file!) function script:Cleanup { $buf.Clear() } # In these small helpers where the logic is straightforward and the correct behavior well known, I occasionally # condense the indentation to something in between the "one liner" and "Microsoft C# guideline" styles filter script:FixComputerName { if ($ComputerName -and $_) { # Handle UNC paths if ($_[1] -eq "") {

    以上是关于PowerShell的推荐编码风格是什么?的主要内容,如果未能解决你的问题,请参考以下文章

    我为什么推荐Prettier来统一代码风格

    前端编码风格规范—— JavaScript 规范

    如何在 PowerShell 字符串文字中编码 Unicode 字符代码?

    优秀 Java 程序员写代码的风格

    推荐10个优秀GitHub仓库

    推荐10个优秀GitHub仓库