我发现自己最近处理了大量 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 '.'}}
Run Code Online (Sandbox Code Playgroud)
sort 表达式效果很好,但是在 shell 中以交互方式工作时需要输入很多内容。我想弄清楚如何将它作为变量或函数添加到我的配置文件中,以便我可以通过更少的输入重新使用它。关键是我正在执行初始 Split 的 string 属性不会总是被调用fqdn。所以我需要一些我仍然可以指定该值的东西。我设想能够输入这样的东西:
$fqdns | sort (fqdnsort fqdn)
Run Code Online (Sandbox Code Playgroud)
PS 我不一定要在表达式本身中寻找效率改进,但如果您有想法,也欢迎这些想法。
您影响的自定义排名行为完全包含在您传递给sort/的参数中Sort-Object- 因此您所要做的就是编写一个返回此类对象的函数:
function Get-FqdnSortKey
{
return @{E={$a=$_.fqdn.Split('.'); [array]::Reverse($a); $a -join '.'}}
}
Run Code Online (Sandbox Code Playgroud)
然后使用像:
$fqdns |Sort-Object (Get-FqdnSortKey)
Run Code Online (Sandbox Code Playgroud)
在进行任何其他功能修改之前,为了清晰起见,让我们稍微重构和重新格式化现有代码:
function Get-FqdnSortKey
{
param()
$SortKeyExpression = {
$a=$_.fqdn.Split('.')
[array]::Reverse($a)
$a -join '.'
}
return @{Expression=$SortKeyExpression}
}
Run Code Online (Sandbox Code Playgroud)
如果要在属性表达式中参数化源属性的名称,则必须使用以下命令关闭函数参数值GetNewClosure():
function Get-FqdnSortKey
{
param(
[string]$PropertyName = 'Fqdn'
)
$SortKeyExpression = {
$a = $_.$PropertyName.Split('.')
[array]::Reverse($a)
$a -join '.'
}.GetNewClosure()
return @{Expression=$SortKeyExpression}
}
Run Code Online (Sandbox Code Playgroud)
这样,当$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
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们已经实现了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
Run Code Online (Sandbox Code Playgroud)
有关在 PowerShell 中使用自定义数据类型的详细信息,请参阅about_Classes帮助主题
| 归档时间: |
|
| 查看次数: |
102 次 |
| 最近记录: |