Powershell对txt文件中的IP地址进行排序

Sae*_*eed 6 sorting powershell ip-address powershell-5.1

我有一个包含一些 IP 的纯文本文件,如下所示:

194.225.0.0 - 194.225.15.255
194.225.24.0 - 194.225.31.255
62.193.0.0 - 62.193.31.255
195.146.53.128 - 195.146.53.225
217.218.0.0 - 217.219.255.255
195.146.40.0 - 195.146.40.255
85.185.240.128 - 85.185.240.159
78.39.194.0 - 78.39.194.255
78.39.193.192 - 78.39.193.207
Run Code Online (Sandbox Code Playgroud)

我想按 IP 地址对文件进行排序。我的意思是只有第一部分很重要。

我用谷歌搜索并找到了一些程序,但我想知道是否可以通过 Powershell 而不使用其他应用程序实现这一点。

我有一个像这样的 Linux 方式,但无法在 Windows 中达到它:

sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 file
Run Code Online (Sandbox Code Playgroud)

更新1

@TheMadTechnician,这是我运行你的命令时的输出:

85.185.240.128 - 85.185.240.159
195.146.40.0 - 195.146.40.255
78.39.193.192 - 78.39.193.207
78.39.194.0 - 78.39.194.255
217.218.0.0 - 217.219.255.255
194.225.24.0 - 194.225.31.255
194.225.0.0 - 194.225.15.255
195.146.53.128 - 195.146.53.225
62.193.0.0 - 62.193.31.255
Run Code Online (Sandbox Code Playgroud)

zet*_*t42 9

使用 RegEx-replace 的简单解决方案:为了使 IP 地址可排序,我们只需在左侧填充每个八位字节,使它们都具有相同的宽度。然后简单的字符串比较就会产生正确的结果。

对于 PS 6+:

Get-Content IpList.txt | Sort-Object {
    $_ -replace '\d+', { $_.Value.PadLeft(3, '0') }
}
Run Code Online (Sandbox Code Playgroud)

对于 PS 5.x:

Get-Content IpList.txt | Sort-Object {
    [regex]::Replace( $_, '\d+', { $args.Value.PadLeft(3, '0') } )
}
Run Code Online (Sandbox Code Playgroud)
  • 该运算符尝试在给定字符串中-replace查找正则表达式模式的匹配项,并用给定值替换它们。
  • 对于PS 5.x,我们需要不同的语法,因为-replace不支持scriptblock。使用.NETRegex.Replace方法我们可以实现同样的目的。
  • 第一个$_表示文本文件的当前行。
  • \d+是匹配每个 IP 地址的每个八位字节的模式。有关详细说明,请参阅regex101中的示例。
  • {}定义输出替换值的 脚本块
    • 这里$_表示当前匹配(八位字节)。我们取它的值,并在左侧用零填充,因此每个八位字节总共为 3 个字符(例如,2becomes00292becomes 092)。最终的 IP 可能如下所示194.225.024.000

使用该类的另一种解决方案Tuple。它稍微长一些,但更干净,因为它实际上比较数字而不是字符串。

Get-Content IpList.txt | Sort-Object {
    # Extract the first 4 numbers from the current line
    [int[]] $octets = [regex]::Matches( $_, '\d+' )[ 0..3 ].Value
    
    # Create and output a tuple that consists of the numbers
    [Tuple]::Create( $octets[0], $octets[1], $octets[2], $octets[3] )  
}
Run Code Online (Sandbox Code Playgroud)
  • 使用[regex]::Matches()我们可以找到当前行的所有数字。从返回的结果中MatchCollection我们取出前四个元素。然后我们使用成员访问枚举Value来创建每个元素的成员的字符串数组MatchCollection

  • 只需将字符串数组分配给具有[int[]]类型约束(s 数组int)的变量,PowerShell 就会自动将字符串解析为整数。

  • 排序之所以有效,是因为Tuple实现了可用时使用的接口。正如预期的那样,元组按字典顺序排序。IComparableSort-Object

  • 使用动态方法调用,我们可以[Tuple]::Create像这样缩短调用(最多适用于 8 个元素1):

     [Tuple]::Create.Invoke( [object[]] $octets )
    
    Run Code Online (Sandbox Code Playgroud)

    请注意转换为[object[]],否则[Tuple]::Create将仅使用单个参数(即$octets数组)进行调用。


[1] 实际上,大于 8 个元素的元组可以通过创建嵌套元组来创建(为剩余元素创建一个元组并将其存储在基本元组的最后一个元素中)。一般来说,要执行此操作,需要递归或反向循环,首先创建大多数嵌套元组。


sco*_*ang 5

这个答案最初是作为我在另一个答案中的评论发布的

您可以将 IP 地址从string对象转换为对象version,该对象“恰好”与 IP 地址具有相同的格式(由 分隔的 4 组数字.

Get-Content .\abc.txt | Sort-Object { [System.Version]($_).split("-")[1] }
Run Code Online (Sandbox Code Playgroud)

  • 恶心。这可能是一个聪明的“技巧”,但滥用这样的类型的可排序性不应该成为人们实际使用的一般建议。遗憾的是,这是得票最高且被接受的答案。当有人重新问这个问题时,“这是我在 PowerShell 中对 IP 地址范围进行排序的方法。我该如何在<其他技术>中做到这一点?” 没有人会(立即)理解“[Version]”在那里做什么。缺乏代码清晰度真的值得吗?我投反对票。 (3认同)