gpt4 book ai didi

powershell - 可重用的自定义排序

转载 作者:行者123 更新时间:2023-12-03 00:31:41 28 4
gpt4 key购买 nike

我发现自己最近处理了大量 DNS 数据,并且我一直在使用自定义排序表达式按名称的每个虚线对 FQDN 进行反向排序,以便同一区域/子区域中的记录彼此相邻排序。例如:

# Build some fake data that normally comes from API call results
# There are generally more columns in the results and they're not always the same
$fqdns = @'
"fqdn","otherdata"
"a.example.com","foo"
"a.example.org","foo"
"example.com","foo"
"example.org","foo"
"www.example.com","foo"
"www.example.org","foo"
"www.sub.example.com","foo"
"www.sub.example.org","foo"
'@ | ConvertFrom-Csv

$fqdns | sort @{E={$a=$_.fqdn.Split('.'); [array]::Reverse($a); $a -join '.'}}
排序表达式效果很好,但是在 shell 中交互工作时需要输入很多内容。我试图弄清楚如何将它作为变量或函数添加到我的配置文件中,以便我可以在输入更少的情况下重复使用它。最重要的是,我正在对其进行初始拆分的字符串属性并不总是被称为 fqdn。 .所以我需要一些我仍然可以指定该值的东西。我设想能够输入这样的内容:
$fqdns | sort (fqdnsort fqdn)
附言我不一定要在表达式本身中寻找效率改进,但如果您有想法,也欢迎。

最佳答案

您影响的自定义排名行为完全包含在您传递给 sort 的参数中。/Sort-Object - 所以你所要做的就是编写一个返回这样一个对象的函数:

function Get-FqdnSortKey
{
return @{E={$a=$_.fqdn.Split('.'); [array]::Reverse($a); $a -join '.'}}
}
然后像这样使用:
$fqdns |Sort-Object (Get-FqdnSortKey)
在进行任何其他功能修改之前,为了清楚起见,让我们稍微重构和重新格式化现有代码:
function Get-FqdnSortKey
{
param()

$SortKeyExpression = {
$a=$_.fqdn.Split('.')
[array]::Reverse($a)
$a -join '.'
}

return @{Expression=$SortKeyExpression}
}
如果要在属性表达式中参数化源属性的名称,则必须使用 GetNewClosure() 关闭函数参数值。 :
function Get-FqdnSortKey
{
param(
[string]$PropertyName = 'Fqdn'
)

$SortKeyExpression = {
$a = $_.$PropertyName.Split('.')
[array]::Reverse($a)
$a -join '.'
}.GetNewClosure()

return @{Expression=$SortKeyExpression}
}
这样,当 $PropertyName在稍后的时间点由结果闭包解决,它仍然具有它在 Get-FqdnSortKey 中的值当我们定义它时。

如果您想为数据添加内在排序行为,您可以通过使用 PowerShell 的 class 定义自定义数据类型来实现。关键字 - 内在排序的唯一要求是我们的类型实现了 System.IComparable界面:
class FqdnWithMetaData : IComparable
{
[string]$Fqdn
[string]$OtherData

hidden [string] $_namespaceOrder = $null

[int]
CompareTo([object]$other)
{
if($other -isnot [FqdnWithMetaData]){
throw [ArgumentException]::new('other')
}

return [string]::Compare($this.GetNamespaceOrder(), $other.GetNamespaceOrder(), [StringComparison]::InvariantCultureIgnoreCase)
}

hidden [string] GetNamespaceOrder()
{
if(-not $this._namespaceOrder){
$labels = $this.Fqdn.Split('.')
[array]::Reverse($labels)
$this._namespaceOrder = $labels -join '.'
}

return $this._namespaceOrder
}
}
现在我们已经实现了 IComparable , Sort-Object只需调用 $current.CompareTo($next)在输入上作为其比较例程的一部分:
$data = @(
[FqdnWithMetaData]@{ Fqdn = 'yahoo.com' },
[FqdnWithMetaData]@{ Fqdn = 'google.com' },
[FqdnWithMetaData]@{ Fqdn = 'google.net' },
[FqdnWithMetaData]@{ Fqdn = 'amazon.com' }
)

$data |Sort-Object # No need to supply anything else here

# Resulting in
Fqdn OtherData
---- ---------
amazon.com
google.com
yahoo.com
google.net
about_Classes help topic有关在 PowerShell 中使用自定义数据类型的更多信息

关于powershell - 可重用的自定义排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63637157/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com