Powershell 正确排序包含版本号的列表
我有一个版本列表,如下所示:Powershell 正确排序包含版本号的列表,powershell,sorting,version-numbering,Powershell,Sorting,Version Numbering,我有一个版本列表,如下所示: v1.1.0 v1.2.0 v1.3.0 v1.4.0 v1.5.0 v1.7.0 v1.8.0 v1.9.0 v2.0.0 v2.1.0 v2.10.0 v2.11.0 v2.12.0 v2.2.0 v2.3.0 v2.4.0 v2.5.0 v2.6.0 v2.7.0 v2.8.0 v2.9.0 $location = Get-Location $path = $location.tostring() + "\CHANGELOG.md" $tags = git
v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
v1.7.0
v1.8.0
v1.9.0
v2.0.0
v2.1.0
v2.10.0
v2.11.0
v2.12.0
v2.2.0
v2.3.0
v2.4.0
v2.5.0
v2.6.0
v2.7.0
v2.8.0
v2.9.0
$location = Get-Location
$path = $location.tostring() + "\CHANGELOG.md"
$tags = git tag
$i = 0
Clear-Content $path
Add-Content $path "Change Log"
Add-Content $path "=========="
Add-Content $path " "
$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$tags | Sort-Object $ToNatural
foreach($tag in $tags)
{
if (-NOT ($tag -match "v(\d+\.)(\d+\.)(\*|\d+)")) { continue }
$i = $i + 1
if ($i -eq 0) { continue }
$tag
If ($i -gt 0) {
$previous = $tags[$i - 1]
Add-Content $path " "
}
}
问题是,它们的订购不正确。
我是Powershell的新手,因此在尝试对其进行排序时遇到了一些问题。
我试着这样做:
$tags = git tag
$versions = $tags | %{ new-object System.Version ($_) } | sort
但我得到了这个错误:
新对象:使用“1”参数调用“.ctor”时发生异常:“版本字符串部分太短或太长。”
第1行字符:24
+$versions=$tags |%{new object System.Version($|)}排序
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+CategoryInfo:InvalidOperation:(:)[New Object],MethodInvocationException
+FullyQualifiedErrorId:ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
有人能帮忙吗
更新 我使用的解决方案如下所示:
v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
v1.7.0
v1.8.0
v1.9.0
v2.0.0
v2.1.0
v2.10.0
v2.11.0
v2.12.0
v2.2.0
v2.3.0
v2.4.0
v2.5.0
v2.6.0
v2.7.0
v2.8.0
v2.9.0
$location = Get-Location
$path = $location.tostring() + "\CHANGELOG.md"
$tags = git tag
$i = 0
Clear-Content $path
Add-Content $path "Change Log"
Add-Content $path "=========="
Add-Content $path " "
$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$tags | Sort-Object $ToNatural
foreach($tag in $tags)
{
if (-NOT ($tag -match "v(\d+\.)(\d+\.)(\*|\d+)")) { continue }
$i = $i + 1
if ($i -eq 0) { continue }
$tag
If ($i -gt 0) {
$previous = $tags[$i - 1]
Add-Content $path " "
}
}
这类工作正常,但所有标记似乎都是控制台记录的,它显示了以下内容:
1.6.0
changeDeliveryFieldAccess
orders/autoComplete
returns/autoComplete
save-lines-dates
services/serviceDetails
tile-colours
users/confirmation
v0.1
v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
v1.7.0
v1.8.0
v1.9.0
v2.0.0
v2.1.0
v2.2.0
v2.3.0
v2.4.0
v2.5.0
v2.6.0
v2.7.0
v2.8.0
v2.9.0
v2.10.0
v2.11.0
v2.12.0
v.2.7.1
正如你所看到的,有一些是我不想要的。具体而言:
1.6.0
changeDeliveryFieldAccess
orders/autoComplete
returns/autoComplete
save-lines-dates
services/serviceDetails
tile-colours
users/confirmation
v.2.7.1
一旦这些从我的列表中清除,那么顺序将正确:)
更新2 因此,我尝试了另一种可能更好的解决方案: $location=获取位置 $path=$location.tostring()+“\CHANGELOG.md” $tags=git标签 $i=0
Clear-Content $path
Add-Content $path "#Change Log"
Add-Content $path "=========="
Add-Content $path " "
$tags |
Where-Object { $_.Substring(1) -as [version] } |
Sort-Object { [version] $_.Substring(1) }
foreach($tag in $tags) {
write-host "$($tag) is ok"
}
我不确定这是否正确,但这是上述代码的输出:
1.6.0 is ok
changeDeliveryFieldAccess is ok
orders/autoComplete is ok
returns/autoComplete is ok
save-lines-dates is ok
services/serviceDetails is ok
tile-colours is ok
users/confirmation is ok
v.2.7.1 is ok
v0.1 is ok
v1.1.0 is ok
v1.2.0 is ok
v1.3.0 is ok
v1.4.0 is ok
v1.5.0 is ok
v1.7.0 is ok
v1.8.0 is ok
v1.9.0 is ok
v2.0.0 is ok
v2.1.0 is ok
v2.10.0 is ok
v2.11.0 is ok
v2.12.0 is ok
v2.2.0 is ok
v2.3.0 is ok
v2.4.0 is ok
v2.5.0 is ok
v2.6.0 is ok
v2.7.0 is ok
v2.8.0 is ok
v2.9.0 is ok
我相信,如果您想对这些字符串进行排序而不出现问题,您需要将它们正确地解析为版本对象
$tags=@(
“v1.1.0”
“v1.2.0”
“v1.3.0”
“v1.4.0”
“v1.5.0”
“v1.7.0”
“v1.8.0”
“v1.9.0”
“v2.0.0”
“v2.1.0”
“v2.10.0”
“v2.11.0”
“v2.12.0”
“v2.2.0”
“v2.3.0”
“v2.4.0”
“v2.5.0”
“v2.6.0”
“v2.7.0”
“v2.8.0”
“v2.9.0”
)
#----------------------------------------------------------------------------#
#解析将失败,因为字符串中的“v”不是有效的语义版本控制
#----------------------------------------------------------------------------#
$tags |%{
$tag=$_
$version=[version]::new()
if([version]::TryParse($tag,[ref]$version))
{
$version
}
其他的
{“ParseFailed--$($tag)”}
}|排序对象
#----------------------------------------------------------------------------#
#已成功解析字符串#
#----------------------------------------------------------------------------#
$tags |%{
$tag=$\替换“[a-zA-Z]”
$version=[version]::new()
if([version]::TryParse($tag,[ref]$version))
{
$version
}
其他的
{“ParseFailed--$($tag)”}
}|排序对象
如果还想将返回的对象用作
2.1.0
类型的字符串,则可以在该对象上添加ToString()
tl;博士:
您后来指出,$tags
数组还包含其他非版本字符串,因此必须过滤掉这些字符串:
只传递那些可以转换为其中对象{$\.Substring(1)-as[version]}
([version]
)对象的字符串-System.version
-在移除开头的-as[version]
后(v
;忽略移除.Substring(1)
是您最初的问题);v
运算符返回成功转换的值或-as
$null
然后将过滤后的标记作为版本号进行排序,这将产生正确的顺序-有关说明,请参阅下一节Sort Object
然后只接收正确排序的原始形式的版本标记(如$sortedVersionTags
前缀字符串)v
版本号中的
v
前缀阻止它们转换为[System.version]
实例;只需首先将其删除(不是从输入本身删除;只是暂时删除,以便创建版本信息对象,例如,v1.1.0
->1.1.0
)
此外,还可以简化您的命令:
# $tags is an array of lines, as output by `git tag`
$tags | Sort-Object { [version] $_.Substring(1) }
是内置在PowerShell中的类型加速器(简称),它引用了[version]
[1][System.version]
- 您只需将字符串强制转换为
,这比使用[version]
更简洁、更快新对象
通过脚本块(排序对象
)接受表达式,以代替要排序的固定属性;在脚本块中,{…}
表示给定的输入对象$\uuu
只需删除第一个字符($\子字符串(1)
)v
- 请注意,该表达式仅暂时用于排序<代码>排序对象仍然输出原始字符串-已排序
v2.10.0
如何在v2.9.0
之后正确排序,这与词汇排序不同):
如果希望输出
System.Version
实例而不是输入字符串,则命令会变得更简单(PSv3+语法):
如果$tags
中包含的所有字符串都可能无法通过这种方式转换(由于没有v
格式),请使用以下(PSv4+语法):
此方法确保遇到无法转换的字符串时不会破坏整个命令:
- 可以转换的是,并且是输出
- 无法转换的内容将导致打印到控制台的错误,并将在以后的自动
集合中反映出来。您可以使用$error
抑制控制台输出2>$null
[1] 一般来说,PowerShell是
[version[]] $tags.Substring(1) | Sort-Object
# Reports non-convertible lines as non-terminating errors, but processes all others.
$tags.ForEach({ [version] $_.Substring(1) }) | Sort-Object
$tags | Sort-Object {[Version]($_ -replace "[a-zA-Z]","")}
v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
...
$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$tags | Sort-Object $ToNatural
v1.1.0
v1.2.0
v1.3.0
...
v2.7.0
v2.8.0
v2.9.0
v2.10.0
v2.11.0
v2.12.0