powershell - 可重用的自定义排序

标签 powershell

我发现自己最近处理了大量 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/

相关文章:

powershell:如何单击 "submit type"输入

excel - 如何使用 powershell 在整个 Excel 工作簿中搜索特定字符串

powershell - $$、$?、$^ 在 powershell 中代表什么?

python - Gitlab CI/CD 在 "Cleaning up project directory and file based variables"和 "ERROR: Job failed: exit code 1"时失败

powershell - select-string如何仅在第一个文件中返回第一个匹配行

powershell - 如何处理文件路径中的空格

arrays - 当数组为空时,是否可以让measure-object为Sum返回0而不是null/nothing?

powershell - Powershell脚本可以将(╯°□°)°┻━┻输出到控制台吗?

powershell - 读取注册表值并转换为日期

arrays - 如何将字符串数组与字符串变量匹配?